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:

  1. Only the winning dog has the same initial letter in name and breed.
  2. The Boxer ranked 1 position after the Shepherd. None of them likes the tunnel, nor jumping through the tire.
  3. Cheetah and the dog who loves the poles were 1st and 3rd.
  4. Thor doesn’t like the plank and didn’t come 2nd.
  5. Cheetah either loves the tunnel or she came 4th.
  6. The dog who loves the plank came 1 position after the dog who loves the poles.
  7. 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

  1. Only the winning dog has the same initial letter in name and breed.
  2. The Boxer ranked 1 position after the Shepherd. None of them likes the tunnel, nor jumping through the tire.
  3. Cheetah and the dog who loves the poles were 1st and 3rd.
  4. Thor doesn’t like the plank and didn’t come 2nd.
  5. Cheetah either loves the tunnel or she came 4th.
  6. The dog who loves the plank came 1 position after the dog who loves the poles.
  7. 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 ))

Quering the Database

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
{'BeanyBreed': 'terrier',
 'BeanyBest': 'tire',
 'BeanyRank': 2,
 'CheetahBreed': 'collie',
 'CheetahBest': 'tunnel',
 'CheetahRank': 1,
 'ThorBreed': 'shepherd',
 'ThorBest': 'poles',
 'ThorRank': 3,
 'SuzieBreed': 'boxer',
 'SuzieBest': 'plank',
 'SuzieRank': 4}

Printing answer in table format

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']}")
Beany  , terrier , tire  , 2
Cheetah, collie  , tunnel, 1
Thor   , shepherd, poles , 3
Suzie  , boxer   , plank , 4