prologzebra-puzzle

Prolog and Logic Puzzles


I seem to be having an issue with the unification of facts in Prolog, but can't confirm it. Everything looks like it should work, and I've looked up examples of solved logic puzzles using Prolog to no real effect, given the relative rarity of Prolog.

This is an extra credit assignment, so I'm unsure if it's valid, but I'm genuinely stumped on how to proceed from here

% Names
name(teo).
name(mira).
name(bruno).
name(igor).

%Food
food(sandwich).
food(pie).
food(hamburger).
food(pizza).

%Hobby
hobby(crosswords).
hobby(writing).
hobby(reading).
hobby(photography).

%Shirt Colour
shirt(white).
shirt(yellow).
shirt(blue).
shirt(red).

%Other
girl(mira).

student((Name, Food, Hobby, Shirt)) :-
    name(Name), food(Food), hobby(Hobby), shirt(Shirt).

solution(L):-
    length(L,4),
    L= [student(teo, sandwich,_,_),_,_,_],
    member(student(mira, pite, crosswords,_),L),
    member(student(girl(GirlName),_,_,white),L),
    member(student(bruno,_,_,yellow),L),
    member(student(_,hamburger,writing,_),
    L= [_, student(_,pie,_,_),_,_],
    next(student(_,pie,_,_), student(teo,_,_,_), L),
    next(student(bruno,_,_,_), student(_,pizza,_,_), L),
    next(student(_,_,_,white), student(_,pizza,_,_), L),
    member(student(igor,_,reading,_),L),
    next(student(_,_,_,blue), student(girl(GirlName),_,_,_), L).

next(A, B, Ls) :- append(_, [A,B|_], Ls).
next(A, B, Ls) :- append(_, [B,A|_], Ls).

The issue is that it won't treat solution(L) as if it's a predicate or a rule, simply a block of text, so I can't even test if it's correct or not. I am most interested in why it won't even function.


Solution

  • At first, I thought this girl/1 is the culprit as many have remarked. But even when removing all such occurrences your definition still fails (and after fixing that syntax error). Here is the responsible part that still fails for solution(L):

    :- op(950, fy, *).
    *(_).
    
    solution(L) :-
       * length(L,4),
       L= [student(_/*teo*/, sandwich,_,_),_,_,_],
       member(student(_/*mira*/, pite, _/*crosswords*/,_),L),
       * member(student(girl(GirlName),_,_,white),L),
       * member(student(bruno,_,_,yellow),L),
       member(student(_,hamburger,_/*writing*/,_),L),
       L= [_, student(_,pie,_,_)|_/*[_,_]*/],
       * next(student(_,pie,_,_), student(teo,_,_,_), L),
       next(_/*student(bruno,_,_,_)*/, student(_,pizza,_,_), L),
       * next(student(_,_,_,white), student(_,pizza,_,_), L),
       * member(student(igor,_,reading,_),L),
       * next(student(_,_,_,blue), student(girl(GirlName),_,_,_), L).
    
    next(A, B, Ls) :- append(_, [A,B|_], Ls).
    next(A, B, Ls) :- append(_, [B,A|_], Ls).
    

    All the names are irrelevant, just as their hobbies. What really matters is the food!

    You have only four places, but a total of five foods (sandwich, pie, pite, hamburger, pizza) - give me just one of them!

    That's the nice thing in Prolog: You can do such generalizations to get a clean diagnosis.