Coding With Children
Programming skills are becomming more and more a part of normal life, and future generations will need to understand and use the basics of computer code or face a major handicap.
I want to introduce my own two children, a seven year old girl and a five year old boy, to writing computer code, however, getting their attention has proved difficult. It is hard to convey the full scope of what can be achieved; I can’t find the right hook to get their attention.
On a recent family trip to Spain I tried a new approach during a thunderstorm which had us trapped indoors with some success. Here’s how it went.
The problem
To begin with I described a game that I wanted to turn into a piece of code, careful not to mention where I was going with the game as previous attempts to talk about coding had been resisted. The game was a simple guessing game.
One person picks a number between one and one hundred and the other person makes guesses until they get the right number. On each turn the words higher or lower are used to point the guesser in the right direction.
This game will allow me to show the use of an algorithm for making guesses, another important element of computer programming, not just simply the writing of the code. Being able to follow an algorithm for the solution is a life skill.
Blind luck could find you the answer more quickly, once in a while, but I want to create the understanding that using my guessing algorithm will find the answer within a fixed number of guesses, whereas the pure luck method could take many more.
Both children liked the concept of the game and we had some fun while the rain fell and thunder growled above. Both started with poor strategies for guessing the number, starting at the extremities and taking a lot of guesses to get to the answer
Through example, I was able to demonstrate that by first picking the middle number, fifty to start with, the number of possible answers is cut in half. By always guessing at the midpoint between the known highest and lowest, you will get to the answer consistently with fewer numbers of guesses.
My seven year old understood this concept but found it difficult to do the necessary computations when narrowing in on the answer after the first guess. Figuring out the midpoint between seventy five and one hundred, for example.
When both were comfortable with the game and had started to show some understanding of the way to find the number, I asked would they like to try writing a computer program for the game. My daughter lost interest when it came time to write some code but my son was happy to join me, at least for a while.
Writing some code
So I had my five year old son to help. We started by seeing if the computer could pick some random numbers. We were using Python 3 so first started playing with the randint
function in the random
package. The arguments it takes are the low and high interger for the possible range. Typing directly at the console we tried:
>>> from random import randint
>>> randint(1, 100)
31
>>> randint(1, 100)
42
>>> randint(1, 100)
35
Running the second line above I showed that the computer could indeed play the game with us. It would not be much of a game if we knew the answer from beginning though, would it? I introduced the notion of a variable next.
>>> answer = randint(1, 100)
Now the number the computer picked was hidden, but could be retrieved. You can show the answer easily:
>>> answer
44
It would be better to write some code to test our guess. First let’s store our guess as another variable.
>>> guess = 55
Did we guess correctly? Time to introduce the equality comparator, ==
.
>>> guess == answer
False
So our guess was incorrect, but was it higher?
>>> answer < guess
False
Then it must have been lower, let’s check.
>>> answer > guess
True
So far my son was with me and understood what I was saying and showing. He is too young to be able to read and write with confidence, however, he did seem to understand the steps I was taking although the notation for equality, greater and less than was new to him.
We used the statements above to play a few games against the computer getting to the answer through various routes. This was not a satisfactory; to make this game fun to play the checking needs to be automated and the feedback needs to be more like a human would give.
Adding user input
Getting input from the user is easy.
>>> guess = input('Enter a guess: ')
Enter a guess: 30
>>> guess
'30'
One issue with this is that it will return a string rather than an integer and that won’t be of much use for numerical comparison. It can be converted to an integer easily enough, however, if a non-number is typed an exception will be thrown. We’ll deal with that later, in the meantime:
>>> guess = int(input('Enter a guess: '))
Enter a guess: 30
>>> guess
30
We are almost there. The guess entry needs to be placed in a loop that continues until the right answer is found. A while
loop can be used to check for equality, and we can check if the guess is higher or lower with an if statement. Remember to ask for a new guess within the while block or you’ll get an infinite loop.
Note that I started to shift the code into a function call at this point as writing control blocks directly into the interpreter is not fun.
while ( answer != guess):
if answer < guess:
print('Wrong! Guess lower.')
else:
print('Wrong! Guess higher.')
guess = int(input('Have another go: '))
Just a few other bits to make the program complete. I want to let the player pick the upper range to start with, passing this as argument to the randint
function.
game_range = int(input('Enter the highest number to choose from: '))
answer = randint(1, game_range)
I also want the computer to count the number of guesses it took and give this as a score. The last thing to add is to ask the player if they want to play again, taking y
to indicate that they do and all other responses to allow the game to end.
Here is the listing that I used to get the game working.
from random import randint
def guessing_game():
playagain = 'y'
while (playagain == 'y'):
game_range = int(input('Enter the highest number to choose from: '))
answer = randint(1, game_range)
guess = int(input('Enter your first guess: '))
guesses = 1
while ( answer != guess):
if answer < guess:
print('Wrong! Guess lower.')
else:
print('Wrong! Guess higher.')
guess = int(input('Have another go: '))
guesses = guesses + 1
print('You got it!', guesses, 'guesses')
playagain = input('Do you want to play again (y/n): ')
print('Goodbye')
Understanding
The above code went over the head of my son, which is probably not a surprise. I think he understood the concept of the computer selecting a random number and storing it without showing it. Also the comparison to figure out whether something was higher or lower seemed to mean something to him even if he didn‘t understand the notation used.
We played a few times before he figured out how to win the game in one guess. When asked for the maximum number, he entered the number one. This meant he only had to guess one. He found this most amusing.
My daughter also got interested in the actual game and played it for a while. While she had no interest in the coding for the game, I think I achieved some success in that she understood that we had created the game from scratch.
A part of learning a new skill is to have some appreciation of what might be possible when the skill is mastered. This vision helps to keep the student on track during the difficult early phases in the learning process when making progress is a struggle.
Another success for this experiment was that I was able to explain the algorithm for searching for the correct guess. By drawing out the search tree I showed both children that the most number of guesses that you would need to find the answer up to one hundred is seven guesses.
The algorithm is to always pick the number half way between lowest and highest and make that guess. Certain numbers will always take seven guesses if the searcher uses this approach.
We drew out the decision tree and they were able to spot the numbers that would be hardest to find - numbers like one or ninety nine, which take seven guesses with my technique.
Further improvements
During our play, we discovered a few issues with the above listing. The program crashes out if a non-integer is passed in at the wrong time. Also the yes or no checking does not check that the user entered n
to exit leading to a few games ending prematurely.
I think that this level of checking is beyond my children’s understanding at the moment, and will make the code a little more difficult to understand. But I’ve gone ahead and added a little before posting below. It is possible that they may revisit this later or that your children are more experienced and can benefit from the lesson.
Rather than use try-catch blocks I have added a simple regular expression matcher to check that the pattern is as expected. A useful resource for help writing regular expressions is regex101, which allows you to see the pattern match a piece of sample text as you write the expression.
There are two examples, the first is to try to match a number from the input. The square brackets marking a class and 0-9
means any digit can apply. The plus symbol requires that one or more characters of that class, numbers, is entered.
r'^[0-9]+$'
Note that the string is preceded with the r
character to represent a raw string. This is the usual way to write a regular expression in Python since the escape character, \
, has meaning in both Python and the regular expression markup. By using the raw format we tell the interpretter not to do any escape character substitutions.
The other expression is used to match y
or n
and can accept upper and lower case:
r'^[ynYN]$'
Note in both cases that it matches the entire string which is denoted by the ^
at the beginning of the line and the $
at the end of the line.
The code was all lumped into a single block above, so I decomposed it into smaller functions. This makes the flow a little easier to read. Over the head of my children at the moment but I’ll try to take them through it again soon.
The idea with the functional decomposition is to ensure that functions have only one purpose, for example, to get a valid guess from the user, or to test for a correct guess.
The final version of the code is available to view as this Github gist.
I toyed with the idea of including the writing of tests as part of this introduction, but decided that it might inhibit their enthusiasm for writing code. First I need to hook their interest before introducing test driven principles.
There is a danger that by not including testing that my children will start with the bad habits of so many of us developers - that we don’t use or fully understand the benefits of test driven development. In justification, I am not trying to create mini-developers; I want to give my children some life skills that I feel will be pre-requisites for many jobs in the future.