帮我完成应用程序的最后一部分吗?它通过暴力破解每个可能的方程来解决第 4 频道上的任何倒计时数字游戏

发布于 2024-11-06 11:02:12 字数 5845 浏览 7 评论 0原文

对于那些不熟悉游戏的人。你有 8 个数字,你必须使用 +、-、/ 和 * 来达到目标​​。

因此,如果目标是 254,而您的游戏数字是 2, 50, 5, 2, 1,您将正确回答问题:5 * 50 = 250。那么 2+2 就是四。添加该内容即可获得 254。

游戏的一些视频位于:

视频1 基本上

我通过生成暴力破解游戏数字的所有大小的所有权限和符号的所有权限,并使用基本的 inflix 计算器来计算解决方案。

然而它包含一个缺陷,因为所有解决方案都按以下方式解决:((((1+1)*2)*3)*4)。它不会排列括号,这让我头疼。

因此我无法解出每个方程。例如,给定

目标 16 和数字 1,1,1,1,1,1,1,1,当它应该执行 (1+1+1+1)*(1+1+1+1 )=16。

我希望有人能帮助完成这个......用任何语言。

这是我到目前为止所写的:

 #!/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);

这是示例输出:

[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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心是晴朗的。 2024-11-13 11:02:12

这里是 Java 小程序 () 和 Javascript 版本。

Here is Java applet (source) and Javascript version.

岁月染过的梦 2024-11-13 11:02:12

使用反向波兰表示法的建议非常好。

如果您有 N=5 个数字,则模板

{num} {num} {ops} {num} {ops} {num} {ops} {num} {ops}

为 任何位置都可以有 0 到 N 个操作,尽管总数为 N-1。你只需要尝试不同的数字和操作位置。

时,将会找到(((1+1)+1)+1)*(((1+1)+1)+1)=16解决方案

1 1 + 1 + 1 + 1 1 + 1 + 1 + *

当您尝试更新:可能不太好,因为找到上述内容可能需要 433,701,273,600 次尝试。该数字是通过以下方式获得的:

use strict;
use warnings;

{
   my %cache = ( 0 => 1 );
   sub fact { my ($n) = @_; $cache{$n} ||= fact($n-1) * $n }
}


{
   my %cache;
   sub C {
      my ($n,$r) = @_;
      return $cache{"$n,$r"} ||= do {
         my $i = $n;
         my $j = $n-$r;
         my $c = 1;
         $c *= $i--/$j-- while $j;
         $c
      };
   }
}

my @nums = (1,1,1,1,1,1,1,1);

my $Nn = 0+@nums;  # Number of numbers.
my $No = $Nn-1;    # Number of operators.

my $max_tries = do {
   my $num_orderings = fact($Nn);
   {
      my %counts;
      ++$counts{$_} for @nums;
      $num_orderings /= fact($_) for values(%counts);
   }

   my $op_orderings = 4 ** $No;

   my $op_placements = 1;
   $op_placements *= C($No, $_) for 1..$No-1;

   $num_orderings * $op_orderings * $op_placements
};

printf "At most %.f tries needed\n", $max_tries;

The suggestion to use reverse polish notation is excellent.

If you have N=5 numbers, the template is

{num} {num} {ops} {num} {ops} {num} {ops} {num} {ops}

There can be zero to N ops in any spot, although the total number will be N-1. You just have to try different placements of numbers and ops.

The (((1+1)+1)+1)*(((1+1)+1)+1)=16 solution will be found when you try

1 1 + 1 + 1 + 1 1 + 1 + 1 + *

Update: Maybe not so good, since finding the above could take 433,701,273,600 tries. The number was obtained using the following:

use strict;
use warnings;

{
   my %cache = ( 0 => 1 );
   sub fact { my ($n) = @_; $cache{$n} ||= fact($n-1) * $n }
}


{
   my %cache;
   sub C {
      my ($n,$r) = @_;
      return $cache{"$n,$r"} ||= do {
         my $i = $n;
         my $j = $n-$r;
         my $c = 1;
         $c *= $i--/$j-- while $j;
         $c
      };
   }
}

my @nums = (1,1,1,1,1,1,1,1);

my $Nn = 0+@nums;  # Number of numbers.
my $No = $Nn-1;    # Number of operators.

my $max_tries = do {
   my $num_orderings = fact($Nn);
   {
      my %counts;
      ++$counts{$_} for @nums;
      $num_orderings /= fact($_) for values(%counts);
   }

   my $op_orderings = 4 ** $No;

   my $op_placements = 1;
   $op_placements *= C($No, $_) for 1..$No-1;

   $num_orderings * $op_orderings * $op_placements
};

printf "At most %.f tries needed\n", $max_tries;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文