Search code examples
prologlogiczebra-puzzle

Prolog Logic Test Example


I have a test coming up on Prolog and I can't really grasp the basic ideas of it. I kind of understand some of the examples I have been going through, but I can't sit down and know off hand how to solve a specific problem.

Our professor gave us some examples and I was wondering if someone could walk me through how to do it so I have some sort of idea how to approach things like this.

The example came from our book:

Donna, Danny, David, and Doreen were seated at a table. 
The men sat across from each other, as did the women. 
They each ordered a different drink and main course.

Facts:

Doreen sat beside the person that ordered steak
The chicken came with a coke
The person with lasagna sat across from the person with milk
David never drinks coffee
Donna only drinks water
Danny could not afford to order steak

I tried something where each person had a list associated with them and you would populate in the facts, but I don't think this is the correct approach. Could someone walk me through this? Thanks!

EDIT:

This is the code I ended up with, it finishes most of the puzzle, it leaves one of the entrees and one of the drinks out, but that should be fixable:

  sat_across([X,_,Y,_], X, Y).
  sat_across([_,X,_,Y], X, Y).

  sat_beside(T, X, Y) :-  % this is tricky
      nth1(N,T,X), nth1(M,T,Y),
      (N =:= M+1 ; N =:= M-1 ; N == 1, M == 4 ; N == 4, M == 1).
      not_connected(T, Place) :- \+ member(Place, T).
  connected(T, Place) :- member(Place, T).

  solve(T) :- T = [_,_,_,_],
      sat_across(T, (danny,_,_), (david,_,_)),
      sat_across(T, (donna,_,_), (doreen,_,_)),
      sat_beside(T, (doreen,_,_), (_,_,steak)),
      connected(T, (_,coke,chicken)),
      sat_across(T, (_,_,lasagna), (_,milk,_)),
      not_connected(T, (david,coffee,_)),
      connected(T, (donna,water,_)),
      not_connected(T, (danny,_,steak)).

Solution

  • Use pattern matching, with each position carrying an attribute triple: Name,Drink,Food.

    Then we have a [N,S,W,E] table (abusing of contract Bridge convention) and we must apply all available constraints: I think could be done this way...

    sat_across([X,_,Y,_], X, Y).
    sat_across([_,X,_,Y], X, Y).
    sat_across([X,_,Y,_], Y, X).
    sat_across([_,X,_,Y], Y, X).
    
    sat_beside(T, X, Y) :-  % this is tricky
        nth1(N,T,X), nth1(M,T,Y),
        (N =:= M+1 ; N =:= M-1 ; N == 1, M == 4 ; N == 4, M == 1).
    
    cant_afford(T, Place) :- \+ member(Place, T).
    
    solve(T) :- T = [N,S,W,E],
          sat_across(T, (danny,_,_), (david,_,_)),
          sat_across(T, (donna,_,_), (doreen,_,_)),
          sat_beside(T, (doreen,_,_), (_,_,steak)),
          ....
          cant_afford(T, (danny,_,steak)),
          ....