Building a chore schedule generator (JavaScript)
Defining the problem
Let’s say you have 6 people working at a basic science lab.
And you have 6 different tasks that need to be done every 2 weeks…
How do you divide the work so that each person takes care of a different task each week, and that the workload is evenly distributed among lab members?
The answer lies in a simple arithmetic operator: “modulo”.
Relying on modulo
If you’re not familiar with the concept, modulo is the operation that we use to find the remainder after dividing number A by number B.
Here are some examples:
3 % 2 = 1
5 % 3 = 2
1 % 3 = 1 (remember that you first have to turn that 1 into a 10 since 1 is less than 3)
OK, but how is modulo useful here?
Modulo can help us by generating indexes (1…n), no matter the dimensions of our desired table.
Let’s explore that through a more visual example. In the following 4x3 table, we have 12 cells that need to be assigned an index. The indexes will later be replaced with the names of the people participating in these activities.
We will be counting from index 0 instead of 1, since this is the way JavaScript works with indexes. Every number will be divided by 3 since that is the number of tasks in this example.
Task 1 | Task 2 | Task 3 |
---|---|---|
0%3 | 1%3 | 2%3 |
3%3 | 4%3 | 5%3 |
6%3 | 7%3 | 8%3 |
9%3 | 10%3 | 11%3 |
Which translates to the following once we perform the operations:
Task 1 | Task 2 | Task 3 |
---|---|---|
0 | 1 | 2 |
0 | 1 | 2 |
0 | 1 | 2 |
0 | 1 | 2 |
But now we have a problem, work is distributed evenly in the sense that everybody will be performing the same amount of tasks in the defined timeframe, but notice how each person has to perform the very same task each week! No fun!
The solution for this is to implement a “sliding window” system through which indexes are offset on every row, to prevent the repetition of tasks. The way I did it was to start at the first cell of each row using the number of that row as the “base index”, and then adding one to that initial index as I filled the rest of the cells in that row:
Here’s how the indexes should be looking after applying that fix:
Task 1 | Task 2 | Task 3 |
---|---|---|
0 | 1 | 2 |
1 | 2 | 0 |
2 | 0 | 1 |
0 | 1 | 2 |
Generating the dates
The labels (dates) for each of the rows were generated using moment.js, a popular JavaScript library for handling dates and times.
The following function was used to get the corresponding Monday and Sunday that mark the start and end of the week(s), depending on a specified interval (tasks need to be performed every 1, 2… n weeks). It also avoids repeating the name of the month if both days in the date range fall within the same month:
Randomization
Since I didn’t want to end up with the same table every time we run the script, I implemented a randomizing algorithm (Fisher-Yates):
Putting it all together
Then, the dates, names and labels for the table are put together.
And now we’ll write the HTML table. At this point, you can specify the length in weeks of your table, and the intervals (how often -in weeks- do tasks need to be performed). Those two values are passed as the third and fourth arguments to assignChores(). In this case, we are generating a table for 10 weeks and at an interval of 2 weeks:
Making it pretty
I added some extra jQuery functionality to let people mark if they have already completed a task, which is represented by a green checkmark that pops up right next to their name when their name is clicked.
And finally, here’s what it looks like with some CSS styling (materialize):