Living in a shared house can sometimes be troublesome; people have different living habits that can conflict with our own. In my house we recently agreed to start a cleaning rota to make sure that we were all doing our bit. The administrative overhead of a rota can be a pain, so I implemented a very simple rota system in Haskell to run as a cron job.
The approach I took was to set up a couple of lists, one of jobs and one of people. The I randomy shuffle the jobs list and cycle through the people assigning the jobs to them by zipping. The actual working code is pretty much a one liner.
I started by installing random-shuffle from Hackage which I will need to provide System.Random.Shuffle, which makes shuffling an Haskell list trivial.
$ cabal install random-shuffle
Next I set to work on rota.hs, by declaring some imports and setting up my lists of people and jobs.
ps = [ "Charlie: "
, "Housemate1: "
, "Housemate2: "
js = [ "Hoover or sweep stairs"
, "Clean cooker"
, "Clean fridge"
, "Hoover hall and landing"
, "Clean and mop kitchen"
, "Clean and hoover front room"
, "Clean and mop upstairs bathroom"
, "Clean and mop downstairs bathroom"
, "Recycling, garden waste, bins and food waste"
, "Trim hedge"
Now, I defined a rota function that randomly shuffles the js list, cycles the ps list, zips them together sorts the resulting list (to group by person) and returns it.
rota = do
return . sort $ zipWith (++) (cycle $ shuffle' ps (length ps) h) (shuffle' js (length js) g)
I also needed a main function, so I could run it as a cron job. All this does is print out a brief explanation, and monadically map over the person/job strings, printing them.
main = do
rs <- rota
putStrLn "This is an automated cleaning rota reminder. Jobs are assigned randomly on the first of the month and a reminder sent out every week or so."
putStrLn "I may have forgotten some important jobs, please tell me if so. Replies to this email ought to come through as expected\n"
mapM_ putStrLn rs
Now I had that bit, I needed to have the script run each month and pipe the output to a file. This file could then be emailed to the housemates on a weekly basis — maybe we will drop the frequency if it turns out to be too annoying. So I added a monthly job to cron, with crontab -e
0 1 1 * * cd /home/charlie/rota && ./rota > cleaning-rotaAnd another job to send the email reminders
0 15 1,8,15,23,28 * * cat /home/charlie/rota/cleaning-rota | mail -s "Reminder: Cleaning Rota" firstname.lastname@example.org
Within less time than it took to write this blog, I was able to build the simplest thing that could possibly work. But of course it remains to be seen whether it actually does work…
Update: Graham pointed out that the original version of this code would mean that if the number of jobs were not divisible by the number of housemates, then the first housemate would get lumbered with the most jobs. So I have changed the code to randomly shuffle the list of housemates too. Thanks Graham!
Image from Shirley on pixabay