in reply to Number from given digits puzzle

Sorry, I have nothing to contribute to tracking down your recursion error. I found the riddle intriguing and tried an independent solution. Here it is:
my $target = 24; my @nums = ( 1, 3, 4, 6); for ( solve( $target, @nums) ) { my $val = eval; print "$_ = $val\n"; } sub solve { my ( $target, @nums) = @_; my @sols; for my $i ( 0 .. $#nums ) { my @rem = @nums; my $first = splice @rem, $i, 1; if ( @rem ) { for ( complements( $target, $first) ) { my ( $op, $try) = @$_; push @sols, map "$first $op $_", map m{[-+*/]} ? "($_)" : $_, solve( $try, @rem); } } else { push @sols, $first if $first eq $target; # sic! } } return @sols; } sub complements { my ( $t, $x) = @_; ( [ '+', $t - $x], [ '-', $x - $t], $x ? [ '*', $t/$x] : (), $t ? [ '/', $x/$t] : (), ); }
Not thoroughly tested, but it finds the solution
6 / (1 - (3 / 4)) = 24
Anno

Replies are listed 'Best First'.
Re^2: Number from given digits puzzle
by Anonymous Monk on Mar 05, 2009 at 03:54 UTC
    That is freakin' genius! I love it!
      Why, thanks. Quite the blast from the past after almost two years :)

      Your praise is unjustified, however, because my solution is wrong. It doesn't find some valid results like (1 + 3)*(4 + 6) = 40 and others that can't be written without an initial parenthesis.

      The correct solution (as I believe) I came up with this time around is comparatively boring. Essentially it builds all arithmetic expressions that can be built from the original numbers, eval's them and sees if they match the target.

      In case anyone has picked up this ancient thread I'm appending it anyway.

      Anno

      sub solve { my ($target, @nums) = @_; return unless @nums; if ( @nums == 1 ) { return unless eval($nums[0]) eq $target; # eq for epsilon fuzz return @nums; } else { my @sol; for my $i ( 0 .. $#nums - 1 ) { for my $k ( $i + 1 .. $#nums ) { my @rem = @nums; my $nk = splice @rem, $k, 1; my $ni = splice @rem, $i, 1; for ( combine($ni, $nk) ) { unshift @rem, $_; push @sol, solve($target, @rem); shift @rem; } } } return @sol; } } sub combine { my ($x, $y) = @_; my ($vx, $vy) = map eval, $x, $y; my @combi = map operate($x, $y, $_), qw(+ *); push @combi, operate($x, $y, '-'); push @combi, operate($y, $x, '-') if $vx ne $vy; push @combi, operate($x, $y, '/') if $vy; push @combi, operate($y, $x, '/') if $vx and $vx ne $vy; @combi; } sub operate { my ($x, $y, $op) = @_; precedes($op, $_) and $_ = "($_)" for $x, $y; $op = " $op " if precedence($op) >= 3; "$x$op$y" } sub precedes { my ($op, $expr) = @_; precedence($op) < precedence($expr); } sub precedence { for ( shift ) { /\-/ and return 4; /\+/ and return 3; /\// and return 2; /\*/ and return 1; return 0; } } __END__