Skip to content

Instantly share code, notes, and snippets.

@ynonp
Created March 28, 2012 07:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ynonp/2224433 to your computer and use it in GitHub Desktop.
Save ynonp/2224433 to your computer and use it in GitHub Desktop.
permutations game
use strict;
use warnings;
use v5.14;
use Algorithm::Combinatorics qw/combinations permutations/;
my @numbers = qw/2 4 6 8/;
my @ops = qw{* - + /};
my $goal = 25;
my %ops = (
'a+b' => sub { @_ == 2 ? $_[0] + $_[1] : "($_[0] + $_[1])" },
'a-b' => sub { @_ == 2 ? $_[0] - $_[1] : "($_[0] - $_[1])" },
'b-a' => sub { @_ == 2 ? $_[1] - $_[0] : "($_[1] - $_[0])" },
'a*b' => sub { @_ == 2 ? $_[0] * $_[1] : "($_[0] * $_[1])" },
'a/b' => sub { @_ == 2 ? $_[0] / $_[1] : "($_[0] / $_[1])" },
'b/a' => sub { @_ == 2 ? $_[1] / $_[0] : "($_[1] / $_[0])" },
);
#######################################################
# Program Main
#
my @parsed_ops = parse_ops(@ops);
OUT: foreach my $np ( permutations( \@numbers ) ) {
foreach my $op ( permutations( \@parsed_ops) ) {
my $sol;
eval {
$sol = solves([@$np], $op, $goal);
};
if ( $sol ) {
say "sol = $sol";
last OUT;
}
}
}
###############################################
# Subroutine Definitions
#
sub solves {
my ($numbers, $ops, $goal) = @_;
my $sol = $numbers[-1];
while ( @$numbers > 1) {
my ($n1, $n2, $op) = (pop $numbers, pop $numbers, pop $ops);
push $numbers, $op->($n1, $n2);
$sol = $op->($sol, $n2, 'p');
}
my $guess = pop $numbers;
if ( abs( $guess - $goal ) < 0.001 ) {
return $sol;
} else {
return;
}
}
sub parse_ops {
my @parsed;
foreach my $op (@_) {
given ($op) {
when ('+') { push @parsed, $ops{'a+b'} };
when ('*') { push @parsed, $ops{'a*b'} };
when ('-') { push @parsed, $ops{'a-b'}, $ops{'b-a'} };
when ('/') { push @parsed, $ops{'a/b'}, $ops{'b/a'} };
}
}
return @parsed;
}
require 'combinatorics'
numbers = %w[2 4 6 8]
ops = %w[* - + / ]
goal = 25
class Operation
def initialize(op, desc)
@op = op
@desc = desc
end
def call(n1, n2)
@op.call(n1, n2)
end
def desc(n1, n2)
@desc.call(n1, n2)
end
end
def solves(numbers, ops, goal)
way = numbers.last
while numbers.count > 1
n1, n2 = numbers.pop, numbers.pop
op = ops.pop
guess = op.call(n1, n2)
numbers.push(guess)
way = op.desc(way, n2)
end
return (numbers.first - goal).abs < 0.001 ? way : false
end
def parse_ops(ops)
parsed = []
ops.each do |op|
case op
when '+'
parsed.push(Operation.new(
lambda { |a, b| a.to_f + b.to_f },
lambda { |a, b| "(#{a} + #{b})"} ) )
when '*'
parsed.push(Operation.new(
lambda { |a, b| a.to_f * b.to_f },
lambda { |a, b| "(#{a} * #{b})"} ) )
when '-'
parsed.push(Operation.new(
lambda { |a, b| a.to_f - b.to_f },
lambda { |a, b| "(#{a} - #{b})"} ) )
parsed.push(Operation.new(
lambda { |a, b| b.to_f - a.to_f },
lambda { |a, b| "(#{b} - #{a})"} ) )
when '/'
parsed.push(Operation.new(
lambda { |a, b| a.to_f / b.to_f },
lambda { |a, b| "(#{a} / #{b})"} ) )
parsed.push(Operation.new(
lambda { |a, b| b.to_f / a.to_f },
lambda { |a, b| "(#{b} / #{a})"} ) )
end
end
return parsed
end
############################
parsed_ops = parse_ops(ops)
numbers.permute(numbers.count).each do |np|
parsed_ops.permute(parsed_ops.count).each do |op|
begin
sol = solves(np.clone, op.clone, goal)
if sol
puts "Sol = #{sol}"
exit
end
end
end
end
#############################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment