Countdown
numbers game solver
version
4B,
notes
updated
2025-03-22
Contestants on the UK Channel 4 TV game show Countdown have 30 seconds in the Numbers Round to work out how to calculate a random target number (or get as close as possible). They may apply addition, subtraction, multiplication or division to some or all of the numbers (each used once only) from a partially random list of six. This document describes a computer program that solves the game. It is the author’s personal endeavour and is in no way affiliated.
The program reads a list of numbers and a target. It finds and displays in human-friendly form all distinct ways of calculating the best solution to the problem.
It is just one of many such programs to be found online today. It started as a 1988 Christmas break project under Xenix on a 12 MHz Intel 80286 CPU. It was a challenge then to write code that would find any solution within half a minute if there was one. Version 1 did this but it took some minutes to conclude without a result when there was no exact solution. Now updated for Linux, the same core solver runs much more quickly on a modern processor. Functional updates have improved completeness and, from much more interesting research, improved human-friendliness in ways described below.
The program’s essential elements (embodied in a search procedure and a display procedure, covered later in more detail) are:
find all sufficiently close candidate solutions by brute force search;
discard those containing ineffectiveness;
discard those that duplicate a solution found earlier;
keep but mark those containing over-complexity; and
present those that remain in human-friendly fashion.
The baseline code reads a problem from its command line and prints the solutions. There is also a text-graphic interface version (not provided) which additionally provides suggested solutions for the Letters Round.
At the program’s core is a brute force search procedure. There are more elegant methods but they are more complex and may be no better in practice. The procedure takes the list of numbers, selects all unordered pairs and applies all allowed arithmetic operations to each pair. For each result it updates a record of how the calculation reached that result. The program also finds single number solutions from the list without any arithmetic. This accommodates a target of 100 when 100 is present in the original list.
Whenever an operation produces an interesting result – one close enough to the target – a display procedure gets called. This procedure checks the calculation. If it is a good candidate solution it is stored in displayable form along with a computed key that is unique to the arithmetic of that solution. “Interesting” starts at “10 away” from the target. This distance reduces whenever a better result is found. Less interesting candidate solutions found thus far get discarded.
If a result is equal to the target, onward search is terminated and the procedure returns to its caller. Otherwise the search procedure calls itself recursively, with a shorter numbers list where the selected pair of numbers is replaced by the result, returning instead when this can no longer be done.
This search covers all possible calculations and will always find every solution. With six numbers and four arithmetic operators, the search could in principle check up to 3,516,066 possible results.
The final list of solutions stored during the search is printed when the search is complete.
The search procedure records its current calculation using a binary tree. The tree is maintained on a stack that grows and shrinks with the recursive search. Each tree node on the stack contains two operands, pointers to where each operand originated (either the list or another node) and an operator. The result currently reached by the search procedure is the one that may be obtained from the top entry of the stack.
When the search procedure calls the display procedure with an interesting result, the display procedure generates an unique key from the stack, using the same code it uses to generate a displayable calculation, but the code operates in a key-specific way.
To generate a key, the binary tree on the stack gets printed to a string as though collapsed into an n-way tree. This results in a sequence of sub-calculations. This is done by by (i) merging connected add and subtract operations; (ii) merging connected multiply and divide operations; and (iii) printing each resulting sub-calculation with its operands numerically sorted. Finally the sub-calculations in the string get alphabetically re-ordered.
This string – the key – is sufficient to identify a set of non-distinct solutions all sharing the same key. The principle (with slightly different implementation) is illustrated nicely by Ben North at https://bennorth.github.io/countdown-numbers-solver/.
The key generation code also generates the displayable solution. It operates as above but the two types of merge are enabled or disabled according to compile-time switches. Also the final alphabetical re-ordering of the sub-calculations is replaced by a human-friendly heuristic to select the best original sub-calculation order to use from the solutions in a non-distinct set.
There are 13,243 distinct ways to select six number-tiles from the standard set. With 900 possible targets there are 11,918,700 distinct games. However, the question addressed here is about how to display just the distinct solutions to one specific game.
To do this the search procedure and the display procedure discard calculations containing different types of ineffectiveness. The display procedure detects duplication and discards candidate solutions that duplicate one previously found. The display procedure keeps but marks candidate solutions containing an over-complexity so the user can decide if these are useful or not.
Ineffectiveness: This arises when an operation makes no progress towards the target. The first type is multiplying (or dividing) a number by one; the second is subtracting two identical numbers; the third is a division that does not produce an integer result. Whenever one of these happens, onward search is terminated, which significantly trims the number of results examined. A fourth type, detected by the display procedure, is an unconnected sub-calculation – some arithmetic that does not get used in obtaining the final result. Such sub-calculations get ignored when processing and storing a candidate solution.
Duplication: The brute force search generates arithmetically identical candidate solutions more than once, amplified by any duplicated numbers in the list. Arithmetically identical candidate solutions have the same key as a stored one. The one that scores best for human-friendliness gets kept.
Over-complexity: This arises when an operation, or a connected sequence of operations, generates a result that duplicates an input into its calculation. Examples include 6–3=3 and 9/3=3. These, in effect, simply discard a number. More convoluted and possibly disputable, the example sequence 8–6=2 then 2x3=6 in effect just discards 8 and 3; or 4x4=16 then 16/8=2 effectively discards a 4. The sequence 3+3=6 then 6+3=9 (i.e. 3+3+3=9 vs 3x3=9) effectively discards a 3 but is not marked because it does not duplicate one of its inputs and so does not qualify according to the current definition. This may need further study.
A question remains about whether the availability of choice in a calculation can lead to duplication or over-complexity not detected as above. For example, (i) when there are two identical numbers in the list; (ii) when a partial calculation generates a result that’s also available as a number from the list; or (iii) when two partial calculations give the same result. The examples below have been updated for some changes here but this may need further study.
In the display procedure, connected sequences of calculations involving just addition and subtraction are merged into a single sub-calculation when printed. Contestants seem to do this. Merging can also be done for sequences containing just multiplication and division. This is less commonly done by contestants and its human-friendliness may be questioned. By default this particular merge is not done.
Human-friendliness is enhanced by selecting from each set of arithmetically identical solutions the one whose displayed sub-calculation order has the lowest heuristic “distance score”. The lowest distance score means that as many sub-calculations as possible are displayed immediately after the sub-calculations that make the results they use. This typically preserves a good arithmetically narrative order – such as a contestant might use to explain a solution. The distance score code also has an element that encourages a sub-calculation display order that approaches the target as quickly as possible, as contestants often seem to do.
Finally, distinct solutions are scored according to a heuristic “user score” for complexity. Solutions with the lowest complexity are displayed first. Contestants typically find the simpler solutions. There are observable aspects of user-friendliness not yet covered, including a tendency for contestants to favour particular forms in the final sub-calculation. This needs further study.
Install a Linux operating system with gcc. Compile from a command line with gcc -O3 -o numbers-tty numbers-tty.c.
To solve example 1 below run “./numbers-tty 1 5 7 9 10 25 =261” from a command line. A problem’s numbers and target may appear in any order with the target identified by a preceding “=”.
There are game policy switches in the code for turning on or off validity checks for the numbers list and for setting its acceptable length. The range of acceptable target values can be specified. The minimum must be 1 or more. A maximum of 0 is interpreted as unlimited. The maximum distance between result and target that makes a solution interesting can be set.
There are constants for enabling or disabling sub-calculation merging (both types) and for the heuristic scoring. The user score heuristic can be tuned. Over-complex solutions may be shown or excluded. Quite a few solution display options can be changed if desired.
To test speed, run “time numbers-tty <problem X> >/dev/null” and record user time.
<problem A>: 1 1 2 2 3 4 =959 (tests searching only – there are no close enough solutions to display)
<problem B>: 2 4 6 8 10 75 =750 (tests searching plus processing to display 225 distinct solutions)
<problem C>: 1 2 3 4 5 6 =7 (tests searching plus processing to display 1015 distinct solutions – needs the default minimum target reduced)
On 2024-07-07 with an Intel Celeron processor N5015: problem A: 8-14 ms; problem B: 35-47 ms; problem C: 132-142 ms.
Reproduced below is a selection from a bigger suite of examples used for testing (hence discontinuous numbering). If “*” is tagged onto to the solution number it contains an over-complexity. Note that the numbering of solutions depends on the “tuning” of the heuristic scoring. This might have changed since the examples were created.
Graeme Cole’s numbers game solver (https://graemecole.uk/countdown/) when asked to find all solutions shows a few differences compared to my examples. The differences seem to be related to showing some solutions with over-complexity but not others. This has not yet been investigated to see if there’s something in the baseline code to be corrected.
Ben North’s solver (https://bennorth.github.io/countdown-numbers-solver/) seems to reproduce my examples. However, there are extra solutions when a number is duplicated in the list (as in several examples below). In these cases the solver shows what I consider to be duplicate solutions arising from choice between two identical numbers in the list, as mentioned earlier.
Target: 261
from 1 5 7 9 10 25
[1] 25+5-1=29 29x9=261
[2]
25+10+1-7=29 29x9=261
[3]* 25+10-5-1=29 29x9=261
[4]
25x10=250 250+7+5-1=261
[5] 25x10=250 250+9+7-5=261
[6]
25+9-5=29 10-1=9 29x9=261
[7] 25x9=225 7x5=35
225+35+1=261
[8] 25+10+1=36 36x7=252 252+9=261
[9]
10+1=11 25x11=275 275-9-5=261
[10] 25+5=30 30x9=270
270+1-10=261
[11] 25+7-5=27 27x10=270 270-9=261
[12]*
10/5=2 25+7-2-1=29 29x9=261
[13] 25-1=24 24x10=240
240+9+7+5=261
[14] 25x7=175 10x9=90 175+90+1-5=261
[15]
25+7=32 9-1=8 32x8=256 256+5=261
[16] 25+5=30 10-1=9
30x9=270 270-9=261
[17] 7x5=35 35-9=26 26x10=260
260+1=261
[18]* 7-5=2 10/2=5 25+5-1=29 29x9=261
[19]
25-7=18 10+5=15 18x15=270 270-9=261
[20] 25+10+7=42 5+1=6
42x6=252 252+9=261
[21]* 25+7=32 9-1=8 32x8=256
256+10-5=261
[22] 25x7=175 10-1=9 9x9=81 175+81+5=261
[23]*
25x9=225 10-5=5 7x5=35 225+35+1=261
[24] 25x10=250 9-7=2
5x2=10 250+10+1=261
[25] 25+1-10=16 9+7=16 16x16=256
256+5=261
[26] 10x5=50 50-9=41 41x7=287 287-25-1=261
[27]
25-1=24 24x9=216 7x5=35 216+35+10=261
[28] 25-7=18
10+5-1=14 18x14=252 252+9=261
[29] 25-9=16 10+7-1=16
16x16=256 256+5=261
[30] 25x5=125 9-7=2 125x2=250
250+10+1=261
[31] 25-7=18 9+5=14 18x14=252 252+10-1=261
[32]
7+1=8 8x5=40 40/10=4 25+4=29 29x9=261
[33] 25-10=15 7-5=2
15x2=30 30-1=29 29x9=261
[34] 10x7=70 70-25=45 5+1=6
45x6=270 270-9=261
[35] 10-7=3 9x3=27 27+25=52 52x5=260
260+1=261
[36]* 25x7=175 175/5=35 35-9=26 26x10=260
260+1=261
[37] 10+7=17 9-1=8 17x8=136 25x5=125
136+125=261
[38] 7x5=35 35-9=26 10+1=11 26x11=286
286-25=261
[39] 7+5=12 25x12=300 300/10=30 30-1=29 29x9=261
Target: 679 from 3 5 7 9 10 50
[1] 10x5=50 50+50-3=97
97x7=679
[2] 9+5=14 50x14=700 7x3=21 700-21=679
[3]
50+7=57 9+3=12 57x12=684 684-5=679
[4] 50x10=500 500/5=100
100-3=97 97x7=679
[5]* 10x5=50 9/3=3 50+50-3=97
97x7=679
[6] 10x9=90 50/5=10 90+10-3=97 97x7=679
[7]
50x9=450 450/5=90 90+10-3=97 97x7=679
[8]* 10+9-5=14
50x14=700 7x3=21 700-21=679
[9]* 50+7=57 9+3=12 57x12=684
684+5-10=679
[10] 10x9=90 90+7=97 50/5=10 10-3=7
97x7=679
[11] 50x9=450 450/5=90 90+7=97 10-3=7
97x7=679
[12]* 50x10=500 500/5=100 9/3=3 100-3=97
97x7=679
[13] 50x7=350 350/5=70 70-3=67 67x10=670
670+9=679
[14] 10x7=70 70-3=67 50/5=10 67x10=670
670+9=679
[15] 50+3=53 53x10=530 530/5=106 106-9=97
97x7=679
[16] 10x9=90 90+50=140 140x5=700 7x3=21
700-21=679
[17] 50x7=350 350-9=341 10/5=2 341x2=682
682-3=679
[18] 50+10=60 60x5=300 300-9=291 291/3=97
97x7=679
[19] 10x9=90 90+5=95 95x50=4750 4750+3=4753
4753/7=679
[20] 50x5=250 10+9=19 250x19=4750 4750+3=4753
4753/7=679
Target: 477 from 8 4 7 4 3 50
[1] 50+3=53 8+4+4-7=9
53x9=477
[2] 50+7-4=53 8+4-3=9 53x9=477
[3] 50+3=53
8/4=2 7+2=9 53x9=477
[4] 50+3=53 4/4=1 8+1=9 53x9=477
[5]
50+3=53 4x4=16 16-7=9 53x9=477
[6]* 50+3=53 8/4=2
7+4-2=9 53x9=477
[7] 50-7=43 8+3=11 43x11=473
473+4=477
[8] 50x8=400 4+4+3=11 11x7=77 400+77=477
[9]
50-8-4=38 38x4=152 152+7=159 159x3=477
[10]* 50+3=53 8/4=2
4/2=2 7+2=9 53x9=477
[11]* 50+3=53 8-4=4 4x4=16 16-7=9
53x9=477
[12] 50+3=53 7x4=28 28+8=36 36/4=9 53x9=477
[13]
50x8=400 7+4=11 4+3=7 11x7=77 400+77=477
[14] 4+4=8
50x8=400 8+3=11 11x7=77 400+77=477
[15] 4+4=8 8x8=64
64-3=61 61x7=427 427+50=477
Target: 701 from 25 9 10 2 3 8
[1] 25x3=75 75+2=77 77x9=693
693+8=701
[2] 10x9=90 90-2=88 88x8=704 704-3=701
[3]
25x9=225 225+8=233 233x3=699 699+2=701
[4] 9x8=72
72x10=720 3x2=6 720+6-25=701
[5] 25+10+9=44 8x2=16
44x16=704 704-3=701
[6] 25x9=225 225x3=675 8x2=16
675+16+10=701
[7] 10x3=30 30-2=28 28x25=700 700+9-8=701
[8]
25x10=250 250-9-8=233 233x3=699 699+2=701
[9] 25x3=75
8/2=4 75+4=79 79x9=711 711-10=701
[10] 8/2=4 25x3=75
75-4=71 71x10=710 710-9=701
[11] 10x2=20 20+9=29 29x25=725
8x3=24 725-24=701
[12] 25-2=23 23x9=207 207x3=621 10x8=80
621+80=701
[13] 25x9=225 225+10=235 235x3=705 8/2=4
705-4=701
Target: 718 from 3 5 3 7 10 75
[1] 75-3=72 72x10=720
720+5-7=718
[2] 75-3=72 72x10=720 720+3-5=718
[3]
75x10=750 7x5=35 750+3-35=718
[4] 75+3-7=71 71x10=710
710+5+3=718
[5] 75-5=70 70x10=700 7x3=21 700+21-3=718
[6]
75x3=225 225x3=675 10x5=50 675+50-7=718
[7] 75x10=750
5+3=8 7-3=4 8x4=32 750-32=718
[8] 75-3=72 72x10=720
7+3=10 10/5=2 720-2=718
[9] 75-3=72 7+3=10 72x10=720
10/5=2 720-2=718
Target: 556 from 10 4 1 7 7 75
[1] 75+4-1=78 78x7=546
546+10=556
[2] 75+4=79 79x7=553 553+10-7=556
[3]
75+7-4=78 78x7=546 546+10=556
[4] 10x7=70 75+70+1-7=139
139x4=556
[5] 10x7=70 7+1=8 70x8=560 560-4=556
[6]
7+7=14 14x10=140 140-1=139 139x4=556
[7] 75x7=525 4-1=3
7x3=21 525+21+10=556
[8] 75+10+7=92 7-1=6 92x6=552
552+4=556
[9] 75x7=525 7-4=3 10x3=30 525+30+1=556
[10]
75-1=74 74x7=518 7x4=28 518+28+10=556
Target: 778 from 10 4 1 7 7 75
[1] 75x10=750 7x4=28
750+28=778
[2] 75+1=76 76x10=760 760+7+7+4=778
[3]
75x10=750 4+1=5 7x5=35 750+35-7=778
[4] 75x10=750 4-1=3
7x3=21 750+21+7=778
[5]* 75x10=750 7+1-4=4 7x4=28
750+28=778
Target: 505 from 75 3 9 1 6 8
[1] 75+9=84 84x6=504
504+1=505
[2] 75-9-3=63 63x8=504 504+1=505
[3] 6+1=7
75x7=525 525-9-8-3=505
[4] 75+9+1=85 85x6=510
510+3-8=505
[5] 9x8=72 72x6=432 432+75+1-3=505
[6]
75+8=83 83x6=498 498+9+1-3=505
[7]* 75+3-9-6=63 63x8=504
504+1=505
[8] 6x3=18 75-18=57 57x9=513 513-8=505
[9]
75-3=72 6+1=7 72x7=504 504+9-8=505
[10] 75+8=83 9-3=6
83x6=498 498+6+1=505
[11] 75-3=72 9+6-8=7 72x7=504
504+1=505
[12] 75-3=72 72x6=432 9x8=72 432+72+1=505
[13]*
75+9=84 6/3=2 8-2=6 84x6=504 504+1=505
[14]* 75+9=84
84x3=252 8-6=2 252x2=504 504+1=505
[15] 9+1=10 10x6=60
60x8=480 75/3=25 480+25=505
[16] 9x6=54 75-54=21 21x3=63
63x8=504 504+1=505
[17] 75x9=675 675-3=672 672/8=84
84x6=504 504+1=505
Target: 849 from 100 3 2 7 10 10
[1] 100+10-3=107 10-2=8
107x8=856 856-7=849
[2] 100+7=107 10-2=8 107x8=856
856+3-10=849
[3] 10-2=8 100x8=800 10-3=7 7x7=49 800+49=849
Target: 669 from 50 100 75 25 7 9
[1] 75x9=675 100+50=150
150/25=6 675-6=669
[2] 100x7=700 50x9=450 450/75=6
700-25-6=669
Target: 794 from 25 100 2 3 2 6
[1] 3x2=6 6+2=8 100x8=800
800-6=794
[2] 6+2=8 100x8=800 3x2=6 800-6=794
[3]
6-2=4 100x4=400 400-3=397 397x2=794
[4] 100+2=102 6+2=8
102x8=816 816+3-25=794
[5] 100-2-2=96 96/3=32 32x25=800
800-6=794
[6] 6x2=12 25x12=300 300+100-3=397 397x2=794
[7]
100+2=102 102/3=34 34-2=32 32x25=800 800-6=794
[8] 2x2=4
100-4=96 96/3=32 32x25=800 800-6=794
[9] 2/2=1 25-1=24
24/3=8 100x8=800 800-6=794
[10] 25x6=150 150x2=300
300-2=298 298x3=894 894-100=794
Target: 663 from 3 5 4 7 100 25
[1] 100x7=700
700-25-5-4-3=663
[2] 100x7=700 4x3=12 700-25-12=663
[3]
25x5=125 125+100-4=221 221x3=663
[4] 100+25+7=132
132x5=660 660+3=663
[5] 4+3=7 100x7=700 700-25-7-5=663
[6]
100+3-4=99 99x7=693 693-25-5=663
[7] 100-3=97 97x7=679
679+5+4-25=663
[8] 7x4=28 25-5=20 28x20=560
560+100+3=663
[9] 100/4=25 25x25=625 7x5=35
625+35+3=663
[10] 7-5=2 100x2=200 200+25-4=221
221x3=663
[11] 100x5=500 25x7=175 4x3=12 500+175-12=663
[12]
25-5=20 100x20=2000 2000-7-4=1989 1989/3=663
[13] 100/5=20
20+7=27 27x25=675 4x3=12 675-12=663
[14] 100x7=700
700/5=140 140+25=165 165x4=660 660+3=663
[15] 100+7=107
107x25=2675 2675-3=2672 2672/4=668 668-5=663
Target: 973
from 75 2 10 9 6 5
[1] 10+9-6=13 75x13=975 975-2=973
[2]
75-10=65 9+6=15 65x15=975 975-2=973
[3] 9x6=54
75+54+10=139 5+2=7 139x7=973
[4] 9+6-2=13 75x13=975 10/5=2
975-2=973
[5] 10/5=2 9+6-2=13 75x13=975 975-2=973
[6]
6x5=30 75+30+2=107 107x9=963 963+10=973
[7] 10x9=90
90+75-2=163 163x6=978 978-5=973
[8] 75x9=675 10x5=50
50x6=300 675+300-2=973
[9] 9+6=15 15/5=3 10+3=13 75x13=975
975-2=973
[10] 75-10=65 65x5=325 9-6=3 325x3=975 975-2=973
John A. Phillips