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__