Skip to content

Instantly share code, notes, and snippets.

@masak
Last active December 17, 2015 19:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masak/5664729 to your computer and use it in GitHub Desktop.
Save masak/5664729 to your computer and use it in GitHub Desktop.
Constraint satisfaction problem http://xkcd.com/287/ solved in Perl 6
class Constraint {
has Real %.coefficients;
has Real $.sum = 0;
}
sub unknown($unknown) {
return Constraint.new( :coefficients{ $unknown => 1 } );
}
multi infix:<+>(Constraint $l, Constraint $r) {
# RAKUDO: Workaround for #118223
$l.coefficients{$_} += 0 for $r.coefficients.keys;
$r.coefficients{$_} += 0 for $l.coefficients.keys;
my %coefficients = $l.coefficients >>+<< $r.coefficients;
Constraint.new( :%coefficients );
}
multi infix:<*>(Constraint $l, Real $r) {
my %coefficients = $l.coefficients >>*>> $r;
Constraint.new( :%coefficients );
}
multi infix:<==>(Constraint $l, Real $sum) {
my %coefficients = $l.coefficients;
Constraint.new( :%coefficients, :$sum );
}
sub solve($constraint) {
sub ranges {
$constraint.coefficients.map: -> ( :key($unknown), :$value ) {
my $max = floor $constraint.sum / $value;
my $range = 0 .. $max;
{ :$unknown, :$range };
}
}
sub sum_of(@solution) {
[+] @solution.map: -> ( :$unknown, :$value ) {
$value * $constraint.coefficients{$unknown}
}
}
multi traverse([], @solution) {
sub is_satisfied { $constraint.sum == sum_of(@solution) }
say @solution.grep(*.<value>).map({ "{.<value>} {.<unknown>}" }).join(", ")
if is_satisfied;
}
multi traverse(@ [$head ( :$unknown, :$range ), *@tail], @solution) {
my $sum_so_far = sum_of(@solution);
for @$range -> $value {
my @augmented = @solution, { :$unknown, :$value };
traverse(@tail, @augmented);
$sum_so_far += $constraint.coefficients{$unknown};
last if $sum_so_far > $constraint.sum;
}
}
traverse(ranges, []);
}
solve
unknown('mixed fruit') * 2.15
+ unknown('french fries') * 2.75
+ unknown('side salad') * 3.35
+ unknown('hot wings') * 3.55
+ unknown('mozarella sticks') * 4.20
+ unknown('sampler plate') * 5.80
== 15.05;
$ time perl6 restaurant
1 mixed fruit, 2 hot wings, 1 sampler plate
7 mixed fruit
real 0m6.972s
user 0m6.384s
sys 0m0.420s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment