Countdown Numbers Game Solver

Version 4B, notes updated 2025-12-27

Overview

Contestants on the UK Channel 4 TV game show Countdown have thirty seconds in the Numbers Round to work out how to calculate a three-digit random target number (or get as close as possible). They may apply addition, subtraction, multiplication and division to some or all of the six numbers (each used at most once) from a partially random selection. This document describes a computer program that finds the best solutions to any given Numbers Round game. It is the author’s personal endeavour and is in no way affiliated.

The program reads the list of numbers and the target. It finds and displays in human-friendly fashion all distinct ways of calculating the closest result.

It is one of many similar programs to be found online today. It started as a 1988 Christmas break project written in C, running under Xenix on a 12 MHz Intel 80286 processor. It was a challenge then to write code that would, within the time limit, find any exact solution 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 migrated to Linux, the same core solver runs much more quickly on a modern processor. Updates have improved the output’s completeness and, from a much more interesting angle, improved its human-friendliness.

The program’s essential steps and solution categorizations, covered later in more detail, are embodied in a search procedure and a display procedure. They are:

The baseline C code reads the problem to solve from its command line and prints the solutions. There is also a text-graphic user interface version (not provided) incorporating the baseline code which can additionally provide suggested solutions for the Letters Round.

Brute Force Search

The program will find single number solutions from the list without arithmetic. This accommodates a target of 100 when 100 is present in the list. It has happened.

However, at the program’s core is a brute force search procedure. It takes a list of numbers, initially the original list, selects all unordered pairs and applies all allowed arithmetic operations to each pair (the correct way round). For each result it updates a record of how the calculation reached that result.

If a result is equal to the target, onward search is terminated and the search procedure returns. Otherwise, either it calls itself recursively with a shorter numbers list where the selected pair of numbers has been replaced by the result, or it returns when the shorter list comprises just one number (the result).

Whenever an operation produces an interesting result – one close enough to the target – a display procedure gets called which checks the calculation. If it is a good candidate solution it gets stored. By default “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.

This search covers all possible calculations and will always find every solution. With six numbers and four arithmetic operators, the search procedure could in principle check up to 3,516,060 calculated results (in addition to the six checks on the numbers in the list).

The final list of stored solutions is printed when the search is complete.

Keeping Track of the Calculation

The search procedure records its current calculation using a binary expression 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 originated (either the list or another tree node) and an operator. The result currently reached by the search procedure is the one that may be calculated from the top entry of the stack.

Distinct Solutions

To produce just distinct solutions the search procedure discards calculations containing some types of ineffectiveness. The display procedure removes other types; detects duplication, keeping just the candidate solution with the most human-friendly presentation; and keeps but marks those containing over-complexity so the user can decide if these are distinct or not.

These are the categorizations above in more detail:

There is a question about whether the availability of choice in a calculation can lead to currently undetected duplication or over-complexity. For example: (i) when there are two identical numbers in the list; (ii) when a partial calculation generates a result that is the same as an unused number in the list; or (iii) when two partial calculations give the same result. The key generation code answers “duplicate” in cases (i) and (iii) but “distinct” in case (ii). This is based on treating the numbers in the list as symbols, while a partial calculation is an expression. This issue may need further study.

Further questions may also need study about exactly what puts a candidate solution into one or more of the categories above, whether the baseline code gets it right or not, and whether there are any missing categories.

The small differences observed between good online solvers may arise from subtly different answers to the elements of the distinct solutions question.

Key Generation

When the search procedure calls the display procedure with an interesting result, the display procedure generates the candidate solution’s key to check if it duplicates a candidate solution already found.

To generate the key, the binary expression tree on the stack gets printed to a string as though collapsed into an n-way expression tree. This results in a set of sub-calculations. It is done by (i) merging connected sequences of add and subtract operations; (ii) merging connected sequences of multiply and divide operations; and (iii) printing each merged sub-calculation with its operations arranged so that its operands are numerically ordered. Finally the sub-calculations in the string get alphabetically re-ordered.

This string – the key – is a canonical way of presenting the solution that is not designed for human-friendliness but does seem to be sufficient to identify a set of duplicate solutions all sharing the same key.

The principle (with slightly different implementation) is illustrated nicely here by Ben North. It also seems to align with the one explained here by Graeme Cole as used in his solver.

Human-Friendly Solution Presentation

The key generation code is also used to generate a solutions presentation. It operates as described above except for some differences described below to make the presentation human-friendly.

Connected sequences of operations involving just addition and subtraction are merged by default into a single sub-calculation. This is done the same way as in key generation. Contestants seem to do this merge and the ordering of operations and operands in a sub-calculation used in key generation is consistent with how contestants typically explain a solution.

Merging as above can also be done for sequences containing just multiplication and division. This is much less commonly done by contestants so by default this particular merge is not done. This is a difference. When a sequence of multiplications and/or divisions arises, whether they get merged or not, there is a question needing further study about whether there is any common pattern to the order in which contestants typically explain the sequence.

No sub-calculation re-ordering is done for solution presentation. This is a difference from key generation. Instead, human-friendliness is maximised by selecting from each set of duplicate solutions the one whose original sub-calculation order has the lowest heuristic distance score. A low distance score arises when as many sub-calculations as possible are placed immediately after the sub-calculations that make the results they use. This typically preserves a good “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 without going too far above, in a way contestants often seem to do.

After the search is complete, distinct solutions are scored for complexity according to a heuristic user score. Solutions with the lowest complexity are printed first. Contestants often find one of the simpler solutions. There is also an observable tendency to favour particular forms in the final sub-calculation. Some elements of this are taken into account but this needs further study.

Compiling and Running

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 10 4 1 7 7 75 =778” from a command line. A problem’s numbers and target may appear in any order with the target identified by a preceding “=”.

Customization

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 solution sub-calculation merging (both types) and for tuning the heuristic scores. Over-complex solutions may be shown or excluded. Quite a few solution display options can be changed.

Speed

To test speed, run “time numbers-tty <problem X> >/dev/null” and record user time. On 2024-07-07 with an Intel Celeron processor N5015:

Problem and Solution Examples

Reproduced below is a selection of problems and solutions from a bigger suite of examples used for testing (hence discontinuous numbering). If “*” is tagged onto to the solution number it contains over-complexity. Note that ordering and presentation depend 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 (2025-06) shows a few differences compared to my examples. The differences all seem to be related to showing some solutions that I categorize as having over-complexity but not showing others (e.g. see example 16 below). 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 (2025-06). However, it also seems to give duplicate solutions whenever a number is duplicated in the list as in several examples below (this is mentioned on his web site).

Example 1

Make 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

Example 2

Make 849 from 100 3 2 7 10 10
[1] 10-2=8 100x8=800 10-3=7 7x7=49 800+49=849
[2] 100+10-3=107 10-2=8 107x8=856 856-7=849
[3] 100+7=107 10-2=8 107x8=856 856+3-10=849

Example 3

Make 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

Example 4

Make 643 from 25 100 9 9 1 1
[1] 25x9=225 225+100=325 1+1=2 325x2=650 650-9=641
[2] 100-1=99 99x9=891 9+1=10 25x10=250 891-250=641

Example 6

Make 477 from 8 4 7 4 3 50
[1] 50x8=400 4+4+3=11 11x7=77 400+77=477
[2] 50+3=53 8+4+4-7=9 53x9=477
[3] 50+7-4=53 8+4-3=9 53x9=477
[4] 50+3=53 8/4=2 7+2=9 53x9=477
[5] 50+3=53 4/4=1 8+1=9 53x9=477
[6] 50-7=43 8+3=11 43x11=473 473+4=477
[7] 50+3=53 4x4=16 16-7=9 53x9=477
[8] 50x8=400 7+4=11 4+3=7 11x7=77 400+77=477
[9] 4+4=8 50x8=400 8+3=11 11x7=77 400+77=477
[10]* 50+3=53 8/4=2 7+4-2=9 53x9=477
[11] 50-8-4=38 38x4=152 152+7=159 159x3=477
[12]* 50+3=53 8/4=2 4/2=2 7+2=9 53x9=477
[13] 4+4=8 8x8=64 64-3=61 61x7=427 427+50=477
[14]* 50+3=53 8-4=4 4x4=16 16-7=9 53x9=477
[15] 50+3=53 7x4=28 28+8=36 36/4=9 53x9=477

Example 7

Make 701 from 25 9 10 2 3 8
[1] 10x3=30 30-2=28 28x25=700 700+9-8=701
[2] 25x9=225 225x3=675 8x2=16 675+16+10=701
[3] 9x8=72 72x10=720 3x2=6 720+6-25=701
[4] 25x3=75 75+2=77 77x9=693 693+8=701
[5] 10x9=90 90-2=88 88x8=704 704-3=701
[6] 25x9=225 225+8=233 233x3=699 699+2=701
[7] 25+10+9=44 44x8=352 352x2=704 704-3=701
[8] 10x2=20 20+9=29 29x25=725 8x3=24 725-24=701
[9] 25x10=250 250-9-8=233 233x3=699 699+2=701
[10] 8/2=4 25x3=75 75-4=71 71x10=710 710-9=701
[11] 25x3=75 8/2=4 75+4=79 79x9=711 711-10=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

Example 8

Make 718 from 3 5 3 7 10 75
[1] 75x10=750 7x5=35 750+3-35=718
[2] 75-3=72 72x10=720 720+5-7=718
[3] 75-3=72 72x10=720 720+3-5=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

Example 9

Make 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] 7+1=8 10x8=80 80x7=560 560-4=556
[5] 75x7=525 4-1=3 7x3=21 525+21+10=556
[6] 75x7=525 7-4=3 10x3=30 525+30+1=556
[7] 10x7=70 75+70+1-7=139 139x4=556
[8] 75+10+7=92 7-1=6 92x6=552 552+4=556
[9] 75-1=74 74x7=518 7x4=28 518+28+10=556
[10] 7+7=14 14x10=140 140-1=139 139x4=556

Example 11

Make 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] 100-2-2=96 96/3=32 32x25=800 800-6=794
[4] 100+2=102 6+2=8 102x8=816 816+3-25=794
[5] 100+2=102 102/3=34 34-2=32 32x25=800 800-6=794
[6] 2x2=4 100-4=96 96/3=32 32x25=800 800-6=794
[7] 2/2=1 25-1=24 24/3=8 100x8=800 800-6=794
[8] 6-2=4 100x4=400 400-3=397 397x2=794
[9] 6x2=12 25x12=300 300+100-3=397 397x2=794
[10] 6x2=12 25x12=300 300-2=298 298x3=894 894-100=794

Example 16

Make 732 from 4 2 9 5 7 7
[1] 9x7=63 63-2=61 7+5=12 61x12=732
[2]* 9x7=63 63+2-4=61 7+5=12 61x12=732
[3] 9x5=45 45+7=52 52x2=104 104x7=728 728+4=732
[4] 4+2=6 9x6=54 54+7=61 7+5=12 61x12=732
[5]* 9x7=63 4/2=2 63-2=61 7+5=12 61x12=732

Quantum Tombolas equivalent solutions (mobile page, 2025-06, with Selection 4 2 9 5 7 7 and Target 732) are:
732
(9 × 7 − 2) × (7 + 5)
(9 × 5 + 7) × 7 × 2 + 4
(9 × (4 + 2) + 7) × (7 + 5)
(9 × 7 + 2 − 4) × (7 + 5)

The output omits solution [5]*, perhaps because of over-complexity from using “4 / 2” instead of just “2”. If so, this is as marked by the baseline code. However the output includes solution [2]* as its fourth solution, with over-complexity from using + 2 4” instead of just “– 2”. This is a difference. It looks like the fourth solution ought to be omitted by Quantum Tombola as an over-complex version of the first. It is not clear whether this arises from a different definition of distinctiveness or over-complexity; or from a design decision; or something else.



John A. Phillips