Play a fun math game with Linux commands
Last Updated on June 18, 2024 by Jim Hall
I like to play puzzle games as a way to take a break when I’m working. One game that I like to play is borrowed from a UK quiz show called Countdown where players are given several random numbers, plus a random target number, and they need to use simple arithmetic to get within 10 of the target number, using the list of numbers at most one time. I find this is a fun math quiz to play on my own, and I’ve written a short script that generates the numbers, to test myself if I can get the target number.
The original game has the random numbers on a set of cards: the “Small” numbers 1 to 10 are included twice and the “Large” numbers 25, 50, 75, and 100 are listed just once. Players can ask for a combination of six numbers picked from “Small” and “Large.” The target number is a randomly generated number from 101 to 999, picked by a computer. I find the game is the most fun with two “Large” and four “Small” numbers; the game is much harder with other combinations, but I’m just in it for fun.
Small numbers
Let’s start by generating the “Small” numbers. This list contains the numbers 1 to 10, twice. The seq
command can generate a list of numbers in any range. If you specify two numbers as arguments, seq
will start and end with those values. Just one number will start counting from 1 until it reaches that value. You can also add a third argument to include a “step” or increment value. You can see the usage in these three examples:
$ seq 3
1
2
3
$ seq 2 5
2
3
4
5
$ seq 3 2 10
3
5
7
9
To list the “Small” numbers, we just need to use seq
twice:
$ seq 10; seq 10
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
To pick just four numbers at random from this list, we first need to use the shuf
command. This randomizes its input, displaying the lines in random order. After that, the head
command can pick off just the first four values from the shuffled list:
$ (seq 10; seq 10) | shuf | head -4
3
6
3
8
Because shuf
shuffles the lines from the input, we’ll get a different set of four “Small” number every time we run this command:
$ (seq 10; seq 10) | shuf | head -4
7
3
2
4
Large numbers
We can use the same method to pick just two random values from the “Large” numbers. Again, the seq
command can generate the list for us, like this:
$ seq 25 25 100
25
50
75
100
And we can use shuf
to randomize the list, and head
to print just the first two numbers from the randomized list:
$ seq 25 25 100 | shuf | head -2
75
100
Every time we run this command, the “Large” numbers will be different:
$ seq 25 25 100 | shuf | head -2
50
25
Target number
We could use a similar method with seq
to list the numbers from 101 to 999, and shuf
and head
to randomize the list and print just one number, but that’s a lot of numbers to print out. But since we just need to generate one random number, we can use another way to get a random value in that range.
The Bash shell will generate a new random value with the RANDOM
variable. Every time you reference this variable, Bash will expand it to be a random number in the range 0 to 32,767:
$ echo $RANDOM
10884
$ echo $RANDOM
23346
Bash also supports simple arithmetic operations, using the $((
and ))
expansion. One of these arithmetic operators is modulo (%
) or the remainder after division. That means 7 modulo 3 is the remainder after dividing 7 by 3, which is 2 with a remainder of 1 (the modulo is 1). The range 101 to 999 is 899 numbers (including the first and last numbers in the list, just as the range 3 to 5 is three numbers: 3, 4, and 5) so let’s start by calculating the modulo of a random number by 899:
$ echo $(( RANDOM % 899 ))
380
Note that arithmetic expansion in Bash automatically expands any variables between the $((
and ))
, so we don’t need to write it as $RANDOM
, but can just use RANDOM
since the arithmetic expansion will reference the value of RANDOM
anyway.
The modulo of 899 will return numbers from 0 to 898, but we want numbers from 101 to 999. That means we need to add 101 to the modulo, like this:
$ echo $(( RANDOM % 899 + 101 ))
493
Putting it all together
With these pieces to print out four random “Small” numbers and two “Large” numbers, we can write a script to do this every time we want to play the Numbers game:
#!/bin/bash
echo "The numbers are:"
seq 25 25 100 | shuf | head -2
(seq 10; seq 10) | shuf | head -4
echo "The target number is:"
echo $(( RANDOM % 899 + 101 ))
This includes some extra echo
statements to label the output for us, but otherwise this is what we wrote above for the “Small” and “Large” numbers. Save this into a file named numbers
and every time you want to play the game, just run the script like this:
$ bash numbers
The numbers are:
75
100
4
8
3
6
The target number is:
452
By the way, I can get close to that, but I don’t think I can get it exactly:
4 x 100 = 400
8 x 3 = 24
75 - 24 = 51
400 + 51 = 451
Let’s try it again with a new list of numbers:
$ bash numbers
The numbers are:
50
100
2
7
4
8
The target number is:
457
That one is easy and just requires a few steps to solve:
4 x 100 = 400
50 + 7 = 57
400 + 57 = 457
Try this fun game for yourself and see how close you can get to your target number.