I wrote an unification-based program as used in Prolog language.
First, I setup a simple unification functions:
Clear[unify];
unify[var1_Symbol, var2_Symbol] :=
If[var1 === var2, {}, {var1 -> var2}];
unify[const1_?StringQ, const2_?StringQ] :=
If[const1 == const2, {}, $Failed];
unify[var_Symbol, const_?StringQ] := {var -> const};
unify[const_?StringQ, var_Symbol] := unify[var, const];
unify[{exp1_, others1___}, {exp2_, others2___}] :=
Module[{car = unify[exp1, exp2], cdr},
If[car === $Failed, Return[$Failed]];
(*else*)
cdr = unify[{others1} /. car, {others2} /. car];
If[cdr === $Failed, Return[$Failed]];
(*else*)
car~Join~cdr
];
unify[{}, {}] = {};
unify[exp_, _Blank] = unify[_Blank, exp_] = {};
"There are five houses" (clue 1), each of which has its resident:
Clear[houses];
houses0 = houses[
{man1, color1, drink1, smoke1, pet1}(*house 1*),
{man2, color2, drink2, smoke2, pet2}(*house 2*),
{man3, color3, drink3, smoke3, pet3}(*house 3*),
{man4, color4, drink4, smoke4, pet4}(*house 4*),
{man5, color5, drink5, smoke5, pet5}(*house 5*)
];
printHouses[h_houses] :=
Transpose@(List @@ h) // Grid[#, Frame -> All] &;
This is our target:
printHouses[houses0]
We have clues:
Clear[clue, houseClue];
dC(*don't Care*)= {_, _, _, _, _};
clue[2] = {"Englishman", "red", _, _, _};
clue[3] = {"Spaniard", _, _, _, "dog"};
clue[4] = {_, "green", "coffee", _, _};
clue[5] = {"Ukrainian", _, "tea", _, _};
clue[6] = houseClue @@ {
{{_, "ivory", _, _, _}, {_, "green", _, _, _}, dC, dC, dC},
{dC, {_, "ivory", _, _, _}, {_, "green", _, _, _}, dC, dC},
{dC, dC, {_, "ivory", _, _, _}, {_, "green", _, _, _}, dC},
{dC, dC, dC, {_, "ivory", _, _, _}, {_, "green", _, _, _}}
};
clue[7] = {_, _, _, "Old Gold", "snail"};
clue[8] = {_, "yellow", _, "Kool", _};
clue[9] = drink3 -> "milk";
clue[10] = man1 -> "Norwegian";
clue[11] = houseClue @@ {
{{_, _, _, _, "fox"}, {_, _, _, "Chesterfield", _}, dC, dC, dC},
{dC, {_, _, _, _, "fox"}, {_, _, _, "Chesterfield", _}, dC, dC},
{dC, dC, {_, _, _, _, "fox"}, {_, _, _, "Chesterfield", _}, dC},
{dC, dC, dC, {_, _, _, _, "fox"}, {_, _, _, "Chesterfield", _}},
{{_, _, _, "Chesterfield", _}, {_, _, _, _, "fox"}, dC, dC, dC},
{dC, {_, _, _, "Chesterfield", _}, {_, _, _, _, "fox"}, dC, dC},
{dC, dC, {_, _, _, "Chesterfield", _}, {_, _, _, _, "fox"}, dC},
{dC, dC, dC, {_, _, _, "Chesterfield", _}, {_, _, _, _, "fox"}}
};
clue[12] = houseClue @@ {
{{_, _, _, _, "horse"}, {_, _, _, "Kool", _}, dC, dC, dC},
{dC, {_, _, _, _, "horse"}, {_, _, _, "Kool", _}, dC, dC},
{dC, dC, {_, _, _, _, "horse"}, {_, _, _, "Kool", _}, dC},
{dC, dC, dC, {_, _, _, _, "horse"}, {_, _, _, "Kool", _}},
{{_, _, _, "Kool", _}, {_, _, _, _, "horse"}, dC, dC, dC},
{dC, {_, _, _, "Kool", _}, {_, _, _, _, "horse"}, dC, dC},
{dC, dC, {_, _, _, "Kool", _}, {_, _, _, _, "horse"}, dC},
{dC, dC, dC, {_, _, _, "Kool", _}, {_, _, _, _, "horse"}}
};
clue[13] = {_, _, "orange juice", "Lucky Strike", _};
clue[14] = {"Japanese", _, _, "Parliament", _};
clue[15] = color2 -> "blue";
clue[16] = {whoDrinksWater, _, "water", _, _};
clue[17] = {whoOwnsZebra, _, _, _, "zebra"};
Then, I did unification one clue after another removing failed results to obtain all the possible answers:
Clear[applyClue];
applyClue[h_houses, clue_List] :=
Module[{u = DeleteCases[unify[clue, #] & /@ (List @@ h), $Failed]},
If[u == {}, $Failed, h /. u]];
applyClue[hs_List, clue_List] :=
DeleteCases[Flatten[applyClue[#, clue] & /@ hs], $Failed];
applyClue[h_houses, clues_houseClue] :=
Module[{u =
List @@ DeleteCases[unify[List @@ h, #] & /@ clues, $Failed]},
If[u == {}, $Failed, h /. u]];
applyClue[hs_List, clues_houseClue] :=
DeleteCases[Flatten[applyClue[#, clues] & /@ hs], $Failed];
possibilities =
Fold[applyClue, houses0 /. {clue[9], clue[10], clue[15]},
Table[clue[
i], {i, {2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 16, 17}}]];
This is the result:
printHouses /@ possibilities
And our interests:
DeleteCases[
List @@ (unify[clue[16], #] & /@ #), $Failed] & /@ possibilities
(*{{{whoDrinksWater -> "Norwegian"}}}*)
DeleteCases[
List @@ (unify[clue[17], #] & /@ #), $Failed] & /@ possibilities
(*{{{whoOwnsZebra -> "Japanese"}}}*)
By the way, I am a Japanese, but I have not obtained my zebra yet!