Zebra puzzle: Difference between revisions

Content added Content deleted
(Add Julia Constraint Programming Version)
(Added Tailspin solution)
Line 6,845: Line 6,845:
4 White Swede Beer Dog BlueMaster
4 White Swede Beer Dog BlueMaster
val it = () : unit
val it = () : unit
</pre>

=={{header|Tailspin}==
A general solver for this type of puzzle, using relational algebra.
<lang tailspin>
processor EinsteinSolver
@: [{|{}|}]; // A list of possible relations, start with one relation with an empty tuple
$ -> \(
when <[](1..)> do
def variableRange: $(1);
@EinsteinSolver: [($@EinsteinSolver(1) join {|{by $variableRange...}|})];
$(2..last) -> #
\) -> !VOID

sink isFact
def fact: $;
def parts: [$... -> {$}];
@EinsteinSolver: [$@EinsteinSolver... -> \(
def new: ($ matching {|$fact|});
@: $;
$parts... -> @: ($@ notMatching {| $ |});
($new union $@) !
\)];
end isFact

operator (a nextTo&{byField:, bMinusA:} b)
@EinsteinSolver: [$@EinsteinSolver... -> \(
def in: $;
def temp: {| $... -> {$, ES_temp__: $(byField)} |};
def numbers: [$temp({ES_temp__:})... -> $.ES_temp__];
$numbers... -> \(
def aNumber: $;
def bNumbers: [$bMinusA... -> $ + $aNumber];
def new: ($temp matching {| {$a, ES_temp__: $aNumber} |});
@: ($new union (($temp notMatching {| $a |}) notMatching {| {ES_temp__: $aNumber} |}));
$numbers... -> \(<~ ?($bNumbers <[<=$>]>)> $! \) -> @: ($@ notMatching {| {$b, ES_temp__: $} |});
($in matching $@) !
\) !
\)];
end nextTo

source solutions&{required:}
templates resolve&{rows:}
when <?($rows <=1>)?($::count <=1>)> do $ !
when <?($::count <$rows..>)> do
def in: $;
def selected: [$...] -> $(1);
@: $;
$selected... -> {$} -> @: ($@ notMatching {| $ |});
[$@ -> resolve&{rows: $rows-1}] -> \(
$ -> \(
when <=[]> do
($in minus {|$selected|}) -> resolve&{rows: $rows} !
otherwise $... -> {| $..., $selected |} -> \(
$ !
($in minus $) -> resolve&{rows: $rows} !
\) !
\) !
\) !
end resolve
[$@EinsteinSolver... -> resolve&{rows: $required}] !
end solutions
end EinsteinSolver

def numbers: [1..5 -> (no: $)];
def nationalities: [['Englishman', 'Swede', 'Dane', 'Norwegian', 'German']... -> (nationality:$)];
def colours: [['red', 'green', 'white', 'yellow', 'blue']... -> (colour:$)];
def pets: [['dog', 'birds', 'cats', 'horse', 'zebra']... -> (pet:$)];
def drinks: [['tea', 'coffee', 'milk', 'beer', 'water']... -> (drink:$)];
def smokes: [['Pall Mall', 'Dunhill', 'Blend', 'Blue Master', 'Prince']... -> (smoke: $)];


def solutions: [$numbers, $nationalities, $colours, $pets, $drinks, $smokes] -> \(
def solver: $ -> EinsteinSolver;

{nationality: 'Englishman', colour: 'red'} -> !solver::isFact
{nationality: 'Swede', pet: 'dog'} -> !solver::isFact
{nationality: 'Dane', drink: 'tea'} -> !solver::isFact
({colour: 'green'} solver::nextTo&{byField: :(no:), bMinusA: [1]} {colour: 'white'}) -> !VOID
{drink: 'coffee', colour: 'green'} -> !solver::isFact
{smoke: 'Pall Mall', pet: 'birds'} -> !solver::isFact
{colour: 'yellow', smoke: 'Dunhill'} -> !solver::isFact
{no: 3, drink: 'milk'} -> !solver::isFact
{nationality: 'Norwegian', no: 1} -> !solver::isFact
({smoke: 'Blend'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'cats'}) -> !VOID
({smoke: 'Dunhill'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'horse'}) -> !VOID
{smoke: 'Blue Master', drink: 'beer'} -> !solver::isFact
{nationality: 'German', smoke: 'Prince'} -> !solver::isFact
({nationality: 'Norwegian'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {colour: 'blue'}) -> !VOID
({drink: 'water'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {smoke: 'Blend'}) -> !VOID

$solver::solutions&{required: 5}!
\);

$solutions... -> ($ matching {| {pet: 'zebra'} |}) ... -> 'The $.nationality; owns the zebra.

' -> !OUT::write

$solutions -> \[i]('Solution $i;:
$... -> '$;
';
'! \)... -> !OUT::write
'No more solutions
' -> !OUT::write
</lang>

{{out}}
<pre>
The German owns the zebra.

Solution 1:
{colour=green, drink=coffee, nationality=German, no=4, pet=zebra, smoke=Prince}
{colour=white, drink=beer, nationality=Swede, no=5, pet=dog, smoke=Blue Master}
{colour=blue, drink=tea, nationality=Dane, no=2, pet=horse, smoke=Blend}
{colour=yellow, drink=water, nationality=Norwegian, no=1, pet=cats, smoke=Dunhill}
{colour=red, drink=milk, nationality=Englishman, no=3, pet=birds, smoke=Pall Mall}

No more solutions
</pre>
</pre>