Solving Logic Puzzles with Symbolic AI (Prolog)
Solving Constraint Satisfication Problem using Prolog.
Problem: https://www.brainzilla.com/logic/logic-grid/agility-competition/
The goal of this exercise is to figure out the combination of: the dog’s name, the breed, the task they were best in, and which place they ranked in. We are given the following clues:
- Only the winning dog has the same initial letter in name and breed.
- The Boxer ranked 1 position after the Shepherd. None of them likes the tunnel, nor jumping through the tire.
- Cheetah and the dog who loves the poles were 1st and 3rd.
- Thor doesn’t like the plank and didn’t come 2nd.
- Cheetah either loves the tunnel or she came 4th.
- The dog who loves the plank came 1 position after the dog who loves the poles.
- Suzie is not a Shepherd and Beany doesn’t like the tunnel
from pyswip import Prolog
from pathlib import Path
Database
To solve any CSP we need to define follwing 3 things.
$X:$ a set of variables $\left\{X_{1}, \ldots, X_{n}\right\}$
$D:$ a set of domains $\left\{D_{1}, \ldots, D_{n}\right\},$ one domain per variable
$C$ is a set of constraints that specify allowable assignments of values to variables
We will define those in our case:
Variables
$X:$ $\left\{name,breed,best,rank\right\}$
Domains
$D_{name}=\{beany,cheetah,thor,suzie\}$
$D_{breed}=\{boxer,collie,shepherd,terrier\}$
$D_{best}=\{plank,poles,tier,tunnel\}$
$D_{rank}=\{1,2,3,4\}$
Constraints
- Only the winning dog has the same initial letter in name and breed.
- The Boxer ranked 1 position after the Shepherd. None of them likes the tunnel, nor jumping through the tire.
- Cheetah and the dog who loves the poles were 1st and 3rd.
- Thor doesn’t like the plank and didn’t come 2nd.
- Cheetah either loves the tunnel or she came 4th.
- The dog who loves the plank came 1 position after the dog who loves the poles.
- Suzie is not a Shepherd and Beany doesn’t like the tunnel
Code
name(beany).
name(cheetah).
name(thor).
name(suzie).
breed(boxer).
breed(collie).
breed(shepherd).
breed(terrier).
best(plank).
best(poles).
best(tire).
best(tunnel).
rank(1).
rank(2).
rank(3).
rank(4).
solve([ [beany,BeanyBreed, BeanyBest, BeanyRank], [cheetah,CheetahBreed, CheetahBest, CheetahRank], [thor,ThorBreed,ThorBest,ThorRank], [suzie,SuzieBreed,SuzieBest,SuzieRank]]):-
breed(BeanyBreed),breed(CheetahBreed),breed(ThorBreed),breed(SuzieBreed),
all_different([BeanyBreed,CheetahBreed,ThorBreed,SuzieBreed]),
best(BeanyBest),best(CheetahBest),best(ThorBest),best(SuzieBest),
all_different([BeanyBest,CheetahBest,ThorBest,SuzieBest]),
rank(BeanyRank),rank(CheetahRank),rank(ThorRank),rank(SuzieRank),
all_different([BeanyRank,CheetahRank,ThorRank,SuzieRank]),
Table = [ [beany,BeanyBreed, BeanyBest, BeanyRank], [cheetah,CheetahBreed, CheetahBest, CheetahRank], [thor,ThorBreed,ThorBest,ThorRank], [suzie,SuzieBreed,SuzieBest,SuzieRank]],
% 1 condition
\+(member([beany,boxer,_,2],Table);member([beany,boxer,_,3],Table);member([beany,boxer,_,4],Table);
member([cheetah,collie,_,2],Table);member([cheetah,collie,_,3],Table);member([cheetah,collie,_,4],Table);
member([thor,terrier,_,2],Table);member([thor,terrier,_,3],Table);member([thor,terrier,_,4],Table);
member([suzie,shepherd,_,2],Table);member([suzie,shepherd,_,3],Table);member([suzie,shepherd,_,4],Table)),
(member([beany,boxer,_,1],Table);member([cheetah,collie,_,1],Table);member([thor,terrier,_,1],Table);member([suzie,shepherd,_,1],Table)),
% 2 condition
\+ member([_,boxer,_,1],Table),
\+ member([_,shepherd,_,4],Table),
\+ member([_,shepherd,tunnel,_],Table),
\+ member([_,shepherd,tire,_],Table),
\+ member([_,boxer,tunnel,_],Table),
\+ member([_,boxer,tire,_],Table),
(member([_,boxer,_,X],Table),member([_,shepherd,_,Y],Table),X is Y+1),
% 3 condition
((CheetahRank == 1,member([_,_,poles,3],Table));
(CheetahRank == 3),member([_,_,poles,1],Table)),
% 4 condition
(ThorBest \== plank),
(ThorRank \== 2),
% 5 condition
(CheetahBest == tunnel;CheetahRank == 2),
% 6 condition
\+ member([[_,_,plank,1]],Table),
\+ member([[_,_,poles,4]],Table),
(member([_,_,plank,X],Table),member([_,_,poles,Y],Table),X is Y+1),
% 7 condition
(SuzieBreed \== shepherd),
(BeanyBest \== tunnel),
show(beany,BeanyBreed,BeanyBest,BeanyRank),
show(cheetah,CheetahBreed, CheetahBest, CheetahRank),
show(thor,ThorBreed,ThorBest,ThorRank),
show(suzie,SuzieBreed,SuzieBest,SuzieRank).
member(X, [X|_]).
member(X, [_|Tail]) :- member(X, Tail).
all_different([H | T]) :- member(H, T), !, fail.
all_different([_ | T]) :- all_different(T).
all_different([_]).
show( X, Y, Z, W) :- write(' '), write(X), write('\t'), write(Y),write('\t'), write(Z),write('\t'), write(W), write('.'), nl.
prolog = Prolog()
# load the database
database_file_path = Path('.')/"database.pl"
prolog.consult(str( database_file_path ))
ans = None
for g in prolog.query("solve([ [beany,BeanyBreed, BeanyBest, BeanyRank], [cheetah,CheetahBreed, CheetahBest, CheetahRank], [thor,ThorBreed,ThorBest,ThorRank], [suzie,SuzieBreed,SuzieBest,SuzieRank]])"):
ans = g
ans
print(f"Beany , {ans['BeanyBreed']:8}, {ans['BeanyBest']:6}, {ans['BeanyRank']}")
print(f"Cheetah, {ans['CheetahBreed']:8}, {ans['CheetahBest']:6}, {ans['CheetahRank']}")
print(f"Thor , {ans['ThorBreed']:8}, {ans['ThorBest']:6}, {ans['ThorRank']}")
print(f"Suzie , {ans['SuzieBreed']:8}, {ans['SuzieBest']:6}, {ans['SuzieRank']}")