The Bash logo

Play a fun math game with Linux commands

0

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.

Leave a Reply