Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help me finish the last part of my app? It solves any Countdown Numbers game on Channel 4 by brute forcing every possibly equation

For those not familiar with the game. You're given 8 numbers and you have to reach the target by using +, -, / and *.

So if the target is 254 and your game numbers are 2, 50, 5, 2, 1, you would answer the question correctly by saying 5 * 50 = 250. Then 2+2 is four. Add that on aswell to get 254.

Some videos of the game are here:

Video 1 video 2

Basically I brute force the game using by generating all perms of all sizes for the numbers and all perms of the symbols and use a basic inflix calculator to calculate the solution.

However it contains a flaw because all the solutions are solved as following: ((((1+1)*2)*3)*4). It doesn't permutate the brackets and it's causing my a headache.

Therefore I cannot solve every equation. For example, given

A target of 16 and the numbers 1,1,1,1,1,1,1,1 it fails when it should do (1+1+1+1)*(1+1+1+1)=16.

I'd love it in someone could help finish this...in any language.

This is what I've written so far:

 #!/usr/bin/env perl

use strict;
use warnings;

use Algorithm::Permute;

# GAME PARAMETERS TO FILL IN
my $target = 751;
my @numbers = ( '2', '4', '7', '9', '1', '6', '50', '25' );


my $num_numbers = scalar(@numbers);

my @symbols = ();

foreach my $n (@numbers) {
    push(@symbols, ('+', '-', '/', '*'));
}

my $num_symbols = scalar(@symbols);

print "Symbol table: " . join(", ", @symbols);

my $lst = [];
my $symb_lst = [];

my $perms = '';
my @perm = ();

my $symb_perms = '';
my @symb_perm;

my $print_mark = 0;
my $progress = 0;
my $total_perms = 0;

my @closest_numbers;
my @closest_symb;
my $distance = 999999;

sub calculate {
    my @oprms = @{ $_[0] };
    my @ooperators = @{ $_[1] };

    my @prms = @oprms;
    my @operators = @ooperators;

    #print "PERMS: " . join(", ", @prms) . ", OPERATORS: " . join(", ", @operators);

    my $total = pop(@prms);

    foreach my $operator (@operators) {
        my $x = pop(@prms);

        if ($operator eq '+') {
            $total += $x;
        }
        if ($operator eq '-') {
            $total -= $x;
        }
        if ($operator eq '*') {
            $total *= $x;
        }
        if ($operator eq '/') {
            $total /= $x;
        }
    }
    #print "Total: $total\n";

    if ($total == $target) {
        #print "ABLE TO ACCURATELY SOLVE WITH THIS ALGORITHM:\n";
        #print "PERMS: " . join(", ", @oprms) . ", OPERATORS: " . join(", ", @ooperators) . ", TOTAL=$total\n";
        sum_print(\@oprms, \@ooperators, $total, 0);
        exit(0);
    }

    my $own_distance = ($target - $total);
    if ($own_distance < 0) {
        $own_distance *= -1;
    }

    if ($own_distance < $distance) {
        #print "found a new solution - only $own_distance from target $target\n";
        #print "PERMS: " . join(", ", @oprms) . ", OPERATORS: " . join(", ", @ooperators) . ", TOTAL=$total\n";
        sum_print(\@oprms, \@ooperators, $total, $own_distance);
        @closest_numbers = @oprms;
        @closest_symb = @ooperators;
        $distance = $own_distance;
    }

    $progress++;
    if (($progress % $print_mark) == 0) {
        print "Tested $progress permutations. " . (($progress / $total_perms) * 100) . "%\n";
    }
}

sub factorial {
    my $f = shift;
    $f == 0 ? 1 : $f*factorial($f-1);
}

sub sum_print {
    my @prms = @{ $_[0] };
    my @operators = @{ $_[1] };
    my $total = $_[2];
    my $distance = $_[3];
    my $tmp = '';

    my $op_len = scalar(@operators);

    print "BEST SOLUTION SO FAR: ";
    for (my $x = 0; $x < $op_len; $x++) {
        print "(";
    }

    $tmp = pop(@prms);
    print "$tmp";

    foreach my $operator (@operators) {
        $tmp = pop(@prms);
        print " $operator $tmp)";
    }

    if ($distance == 0) {
        print " = $total\n";
    }
    else {
        print " = $total (distance from target $target is $distance)\n";
    }
}

# look for straight match
foreach my $number (@numbers) {
    if ($number == $target) {
        print "matched!\n";
    }
}

for (my $x = 1; $x < (($num_numbers*2)-1); $x++) {
    $total_perms += factorial($x);
}

print "Total number of permutations: $total_perms\n";
$print_mark = $total_perms / 100;
if ($print_mark == 0) {
    $print_mark = $total_perms;
}

for (my $num_size=2; $num_size <= $num_numbers; $num_size++) {
    $lst = \@numbers;
    $perms = new Algorithm::Permute($lst, $num_size);

    print "Perms of size: $num_size.\n";

    # print matching symb permutations
    $symb_lst = \@symbols;
    $symb_perms = new Algorithm::Permute($symb_lst, $num_size-1);

    while (@perm = $perms->next) {
        while (@symb_perm = $symb_perms->next) {
            calculate(\@perm, \@symb_perm);
        }

        $symb_perms = new Algorithm::Permute($symb_lst, $num_size-1);
    }
}

print "exhausted solutions";
print "CLOSEST I CAN GET: $distance\n";
sum_print(\@closest_numbers, \@closest_symb, $target-$distance, $distance);
exit(0);

Here is the example output:

[15:53: /mnt/mydocuments/git_working_dir/countdown_solver$] perl countdown_solver.pl
Symbol table: +, -, /, *, +, -, /, *, +, -, /, *, +, -, /, *, +, -, /, *, +, -, /, *, +, -, /, *, +, -, /, *Total number of permutations: 93928268313
Perms of size: 2.
BEST SOLUTION SO FAR: (2 + 4) = 6 (distance from target 751 is 745)
BEST SOLUTION SO FAR: (2 * 4) = 8 (distance from target 751 is 743)
BEST SOLUTION SO FAR: (4 + 7) = 11 (distance from target 751 is 740)
BEST SOLUTION SO FAR: (4 * 7) = 28 (distance from target 751 is 723)
BEST SOLUTION SO FAR: (4 * 9) = 36 (distance from target 751 is 715)
BEST SOLUTION SO FAR: (7 * 9) = 63 (distance from target 751 is 688)
BEST SOLUTION SO FAR: (4 * 50) = 200 (distance from target 751 is 551)
BEST SOLUTION SO FAR: (7 * 50) = 350 (distance from target 751 is 401)
BEST SOLUTION SO FAR: (9 * 50) = 450 (distance from target 751 is 301)
Perms of size: 3.
BEST SOLUTION SO FAR: ((4 + 7) * 50) = 550 (distance from target 751 is 201)
BEST SOLUTION SO FAR: ((2 * 7) * 50) = 700 (distance from target 751 is 51)
BEST SOLUTION SO FAR: ((7 + 9) * 50) = 800 (distance from target 751 is 49)
BEST SOLUTION SO FAR: ((9 + 6) * 50) = 750 (distance from target 751 is 1)
Perms of size: 4.
BEST SOLUTION SO FAR: (((9 + 6) * 50) + 1) = 751
like image 270
Philluminati Avatar asked May 09 '11 15:05

Philluminati


People also ask

Can the countdown numbers always be solved?

There is no target number that it is impossible to make, given the correct numbers. Only one set of number {1,1,2,2,3,3} cannot make any target solution (as it's not possible to make any three digit number from this set of numbers). If you were unlucky enough to draw these numbers there is nothing you could do.

How does the countdown solver work?

With this tool you can enter inputs from Countdown letters and numbers games and have solutions calculated. The numbers game solver is able to solve any solvable game. The letters game solver (in addition to the letters game) is also useful for solving the Countdown Conundrum and the Teatime Teaser.

How many points is a countdown number game?

10 points are given for an exact answer, 7 points for a non-exact solution up to 5 from the target, and 5 points for a solution between 6 and 10 from the target. If neither contestant can get within 10, no points are awarded.


1 Answers

Here is Java applet (source) and Javascript version.

like image 171
jm666 Avatar answered Oct 19 '22 05:10

jm666