fun adjacent (space,#[a,b])=
let
val tmp = FD.range(space,(~4,4))
val one = FD.range(space,(1,1))
in
post(space,FD(a) `- FD(b) `= FD(tmp),FD.DOM);
FD.abs(space,tmp,one,FD.DOM)
end
fun zebra_puzzle space =
let
val nationality =
{engl=FD.range(space,(0,4)),span=FD.range(space,(0,4)),
jap=FD.range(space,(0,4)),ital=FD.range(space,(0,4)),
norw=FD.range(space,(0,4))}
val color =
{green=FD.range(space,(0,4)),red=FD.range(space,(0,4)),
yellow=FD.range(space,(0,4)),blue=FD.range(space,(0,4)),
white=FD.range(space,(0,4))}
val profession =
{painter =FD.range(space,(0,4)),diplomat=FD.range(space,(0,4)),
violinist =FD.range(space,(0,4)),doctor=FD.range(space,(0,4)),
sculptor=FD.range(space,(0,4))}
val animal =
{dog=FD.range(space,(0,4)),zebra=FD.range(space,(0,4)),
fox=FD.range(space,(0,4)),snails=FD.range(space,(0,4)),
horse=FD.range(space,(0,4))}
val drink =
{juice=FD.range(space,(0,4)),water=FD.range(space,(0,4)),
tea=FD.range(space,(0,4)),coffee=FD.range(space,(0,4)),
milk=FD.range(space,(0,4))}
fun makevector() =
let val a = (fn x => #[#engl(x),#ital(x),#jap(x),#norw(x),
#span(x)])nationality
val b = (fn x => #[#green(x),#red(x),#yellow(x),#blue(x),
#white(x)])color
val c = (fn x => #[#painter(x),#diplomat(x),#violinist(x),
#doctor(x),#sculptor(x)])profession
val d = (fn x => #[#dog(x),#zebra(x),#fox(x),#snails(x),
#horse(x)])animal
val e = (fn x => #[#juice(x),#water(x),#tea(x),#coffee(x),
#milk(x)])drink
in
#[a,b,c,d,e]
end
val varvec = makevector()
in
(* the following constraint ensures that the properties
within one group hold for different houses*)
Vector.app(fn x => FD.distinct(space,x,FD.BND))
varvec;
(* the next 15 constraints ensure the known
facts mentioned in the problem specification *)
FD.rel(space,#engl(nationality),FD.EQ,#red(color));
FD.rel(space,#dog(animal),FD.EQ,#span(nationality));
FD.rel(space,#painter(profession),FD.EQ,#jap(nationality));
FD.rel(space,#tea(drink),FD.EQ,#ital(nationality));
FD.relI(space,#norw(nationality),FD.EQ,0);
FD.rel(space,#green(color),FD.EQ,#coffee(drink));
FD.rel(space,#green(color),FD.GR,#white(color));
FD.rel(space,#sculptor(profession),FD.EQ,#snails(animal));
FD.rel(space,#diplomat(profession),FD.EQ,#yellow(color));
FD.relI(space,#milk(drink),FD.EQ,2);
adjacent(space,#[#norw(nationality),#blue(color)]);
FD.rel(space,#violinist(profession),FD.EQ,#juice(drink));
adjacent(space,#[#fox(animal),#doctor(profession)]);
adjacent(space,#[#horse(animal),#diplomat(profession)]);
FD.rel(space,#zebra(animal),FD.EQ,#white(color));
FD.branch(space,Vector.concat(Vector.toList(varvec)),
FD.B_SIZE_MIN,FD.B_MIN);
{nationality,color,profession,animal,drink}
end
The script defines a search tree with 29 nodes.
The unique solution is the record
{animal = {dog = 2, fox = 4, horse = 3, snails = 1, zebra = 0},
color = {blue = 1, green = 4, red = 3, white = 0, yellow = 2},
drink = {coffee = 4, juice = 0, milk = 2, tea = 1, water = 3},
nationality = {engl = 3, ital = 1, jap = 4, norw = 0, span = 2},
profession = {diplomat = 2, doctor = 3, painter = 4, sculptor = 1, violinist = 0}}
Andreas Rossberg 2006-08-28