Programming the Twelve Days of Christmas

If commercial television and supermarket shelves are to be believed, it's been Christmas for a good few weeks now, so it's time that teachers start planning a Christmas activity. With ICT, I always felt that most Christmas-related activities were either trivial, contrived, or only tenuously-related to Christmas, but here's a suggestion that's a genuine programming activity that can be easily adapted or extended to suit a range of abilities - I do it at KS3 - and can be done in a single lesson as a simple programming exercise with more guidance, or over a number of lessons with some analysis and a report justifying the techniques used.

The Task

The idea for the task came from my daughter's Christmas homework when she was in year 1 or 2. She was to calculate the total number of presents in the song The Twelve Days of Christmas, so we set about making a web-page to show her teacher how we'd worked it out.

Displaying the numbers of the days and the presents started out as a way of checking that we hadn't missed anything, but I then realised that it could be used to demonstrate the use of arrays (or lists, if you're using Python) for the "look-up" of descriptions for the presents.

You could therefore ask students to complete some or all of the following things:

Analysis

If you want to make this take a bit longer than a lesson, there is scope for some analysis. Before doing the homework with my daughter, I'd always assumed that every present was given every day - i.e. the partridge in the pear tree was given every day, so that on the second day the true love is given the turtle doves and the partridge. Another interpretation seems to be that only the first present is given on each day, and the song then merely recaps the presents given on previous days.

Design

This task could be used as an introduction to (or revision of) nested loops. I always use a for loop wherever possible, but I find that a lot of self-taught students are obsessed with using while, even for simple "counting" loops such as this. Nested loops are much messier using while, requiring extra assignments and decisions, so it's a good idea to try to help them break the habit.

The basic structure of the song requires you to count upwards for the days from 1 to 12, and then back down to one for the number of presents.

If you're giving the user the choice of whether to count the repetitions of presents, you could revise the use of Boolean variables (if your language allows them), and the idea that you don't need the comparison operator with Boolean variables, e.g. if your variable was called count_repeats, you could use:

if count_repeats:

rather than:

if count_repeats == True:

Alternatively, you could demonstrate that Boolean variables are stored as integers, with False being 0 and True usually being 1 (e.g. in Python) or "1 (e.g. in Visual Basic). This means that you can multiply a number by a Boolean variable - e.g. if gift was the number of presents, then gift * count_repeats would give 0 if count_repeats was False, and gift if it was True. If your language uses "1 for True, as Visual Basic does, then simply use the absolute function, e.g. Maths.Abs(gift * count_repeats).

When asking the question, it's also worth reminding students that comparisons (e.g. anything using =/==, >, <, etc.) are first evaluated as being True or False. This means that Boolean operators are always operating on True or False, as they are in truth tables, but it also means that you can assign the result of a comparison to a Boolean variable, e.g. positive = number > 0. This is the technique I've used in my sample program at the bottom of the page. I've also changed the answer to upper case so that I don't have to check for both Y and y.

The main focus of this activity for me, however, is using an array or list to look up the name of the present for a given day. This is a classic example of using a number (e.g. that you've counted, calculated or generated randomly) as an index for an array or list. All you need do is put the names of the presents in a list or array, e.g.

present = ("partridge in a pear tree", "turtle doves", "French hens", "colly birds")

Remember that indexes often start at zero, so you have two options - subtract one from the present number to give your index, or put a dummy item at the start of the list. Ask your class which would be better - using additional memory or additional processor time (the answer might depend on the platform used)?

A third option would be to count from 0 to 11, rather than 1 to 12, but that would make calculating the total number of presents a bit more complex.

With beginners, or lower-ability students, you might be happy with something like:

"On day 2 of Christmas my true love gave to me 2 turtle doves"

but from more competent students I'd be hoping for:

"On the second day of Christmas my true love gave to me, two turtle doves"

Again, you could put the ordinal numbers in a list and look them up:

ordinal = ("zeroth", "first", "second", "third"...)

For the cardinal numbers, you could do the same, or you could just add them to the names of the presents in the first list/array, e.g.

present = ("a partridge in a pear tree", "two turtle doves", "three French hens", "four colly birds"...)

Finally, any extra features, such as images, will need to be discussed in a manner that's relevant to your programming environment.

Implementation

I would start my program with the nested loops and simply print the numbers to check the structure of your program - e.g. you could get a sequence such as 1, 1, 2, 2, 1, 3, 3, 2, 1, 4, 4, 3, 2, 1, etc., where the number in bold is the day and the other numbers represent the number of presents. I might even add some formatting to separate the verses at this stage, and if I were going to calculate the total number of presents I'd also do that at this point. You could hard"code the value of the Boolean variable for testing purposes, or ask the user.

I'd finally add the arrays/lists to represent the gifts and the ordinal numbers, and any other bells and whistles such as images.

Testing

The scope for testing a program like this is quite limited, because there will only be one or two possible outputs, depending on how and whether you've chosen to calculate the total number of presents.

It might be a good opportunity to discuss the difference between qualitative and quantitative tests. If you're counting up the presents, then obviously it's important that you get the right answer (I make it either 78 or 364, depending on whether you count the repeated presents), but with something festive it's also important that it looks nice, the text is readable, the verses are clearly separated, etc.

Finally

You might not like this task, or may have different ideas about how it's done, but hopefully it's given you some ideas for possible programming tasks, whether festive or not. If you feel that you can add to this blog, why not start a thread in your favourite forum (or comment below)?

Possible Solution

This is a possible solution coded in Python, although it could easily be adapted to work in other languages by swapping the lists for arrays. Note that I've used print()so that it works in both Python 2 and 3 - all you need to do to get the program to work in Python 2 is change input() to raw_input().

ordinal = ("", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth")
present = ("", "a partridge in a pear tree", "two turtle doves", "three French hens", "four colly birds", "five gold rings", "six geese a-laying", "seven swans a-swimming", "eight maids a-milking", "nine ladies dancing", "ten lords a-leaping", "eleven pipers piping", "twelve drummers drumming")
total = 0

count_repeats = input("Would you like to count repeated presents? (Y/N) ").upper() == "Y"

for day in range(1, 13):
    total += day
    print("\nOn the", ordinal[day], "day of Christmas my true love gave to me...")
    for gift in range(day, 0, -1):
        print("- ", present[gift])
        if gift < day:
            total += gift * count_repeats
print("\nThe total number of presents is " + str(total) + ".")

This blog originally appeared in the TES Subject Genius series in December 2015.