Zebra puzzle: Difference between revisions

Content added Content deleted
(add mercury)
(→‎{{header|Raku}}: Make use of temp over clone. Variable renaming.)
Line 6,060: Line 6,060:
for gather solve(@houses, @facts) {
for gather solve(@houses, @facts) {
#-- output
#-- output
say .[0].pairs.sort.map(*.key.uc.fmt("%-9s")).join(' | ');
say .head.sort.map(*.key.uc.fmt("%-9s")).join(' | ');
say .pairs.sort.map(*.value.fmt("%-9s")).join(' | ')
say .sort.map(*.value.fmt("%-9s")).join(' | ')
for .list;
for .list;
last; # stop after first solution
last; # stop after first solution
Line 6,067: Line 6,067:
}
}


#| found a solution that fits all the facts
#| a solution has been found that fits all the facts
multi sub solve(@solution, @facts [ ]) {
multi sub solve(@solution, @facts [ ]) {
take @solution;
take @solution;
}
}


#| extend a scenario to cover the next fact
#| extend this scenario to fit the next fact
multi sub solve(@scenario, [ $fact, *@facts ] is copy) {
multi sub solve(@scenario, [ $fact, *@facts ] is copy) {
for gather choices(@scenario, |$fact) {
for gather suppose(@scenario, |$fact) -> @houses {
solve(@$_, @facts)
solve(@houses, @facts)
}
}
}
}


#| find all possible solutions for pairs of houses with
#| find all possible solutions for pairs of houses with
#| %a attributes, left of a house with %b attributes
#| lemma %a, left of a house with lemma %b
multi sub choices(@houses, :Left-Of(%b)!, *%a) {
multi sub suppose(@houses, :Left-Of(%b)!, *%a) {
for @houses {
for @houses {
my $idx = .<num> - 1;
my $idx = .<num> - 1;
if $idx > 0 && plausible(@houses[$idx-1], %a) && plausible(@houses[$idx], %b) {
if $idx > 0 && plausible(@houses[$idx-1], %a) && plausible(@houses[$idx], %b) {
my @scenario = @houses.clone;
temp @houses[$idx-1].Hash ,= %a;
@scenario[$idx-1] = %( %(@houses[$idx-1]), %a );
temp @houses[$idx].Hash ,= %b;
@scenario[$idx] = %( %(@houses[$idx]), %b );
take @houses;
take @scenario;
}
}
}
}
}
}


#| suppose these houses are next to each other (left or right)
#| find all possible pairs of houses with %a attributes, either side
multi sub suppose(@houses, :Next-To(%b)!, *%a ) {
#! of a house with %b attributes
multi sub choices(@houses, :Next-To(%b)!, *%a ) {
suppose(@houses, |%a, :Left-Of(%b) );
choices(@houses, |%a, :Left-Of(%b) );
suppose(@houses, |%b, :Left-Of(%a) );
choices(@houses, |%b, :Left-Of(%a) );
}
}


#| find all possible houses that match the given attributes
#| find all possible houses that match the given attributes
multi sub choices(@houses, *%fact) {
multi sub suppose(@houses, *%lemma) {
for @houses.grep({plausible($_, %fact)}) -> $house {
for @houses.grep({plausible($_, %lemma)}) -> $house {
my @scenario = @houses.clone;
my $idx = $house<num> - 1;
my $idx = $house<num> - 1;
@scenario[$idx] = %( %$house, %fact );
temp @houses[$idx] = %( %$house, %lemma );
take @scenario;
take @houses;
}
}
}
}


#| plausible if doesn't conflict with anything
#| plausible if doesn't conflict with anything
sub plausible(%house, %atts) {
sub plausible(%house, %lemma) {
all %atts.keys.map: { (%house{$_}:!exists) || %house{$_} eq %atts{$_} };
! %lemma.first: {%house{.key} && %house{.key} ne .value };
}
}
</lang>
</lang>