Search code examples
prologzebra-puzzle

How to solve this puzzle using prolog?


I am trying to solve this prolog puzzle and I am now stuck. I have tried writing different rules and solutions but it is not printing the solution. I am new to this language so any help would be greatly appreciated. I included what I have so far below. This is the puzzle... A group of friends attends a cooking class! Based on the facts below, determine the full name of each person, their favorite seasonings and the favorite recipe each made with that seasoning.

  1. The one who loved paprika made delicious vegetable lasagna, but it wasn't Arthur.
  2. Stan, whose last name wasn't Night, didn't cook with spearmint.
  3. Mr. Bradley loved cooking with cinnamon.
  4. Jake, whose last name wasn't Manor, loved to cook with basil but his favorite recipe wasn't grilled swordfish.
  5. Paul made hobo potatoes but not using spearmint. Arthur's last name wasn't Night.
  6. Frank Jones didn't make grilled swordfish.
  7. Stan, whose last name wasn't Manor, made an awesome slow roasted pork loin but not using sage.
  8. Mr. Summer, whose first name wasn't Arthur, made a great seasoned chicken but not using sage.

This is what I have so far...

name[authur]
name[frank]
name[jake]
name[paul]
name[stan]

lname[bradley].
lname[jones].
lname[manor].
lname[night].
lname[summer].

snack[swordfish]
snack[potato]
snack[roast pork]
snack[chicken]
snack[lasagna]

seasoning[basil].
seasoning[cinnamon].
seasoning[paprika].
seasoning[sage].
seasoning[spearmint].

And here is a picture of the puzzle and I appreciate any help. Thank you.

enter image description here


Solution

  • Taking almost directly from Metalevel's Zebra Puzzle section at the end of that page, it can be solved with Constraints by giving each thing a value 1-5 and then making the values equal or different.

    Taken from the clue hints, Jake doesn't have the same value as Swordfish, Stan does have the same value as Pork, etc. The most effort is getting the results out, and there's probably a nicer way than I have:

    :- use_module(library(clpfd)).
    
    solve(Pairs) :-
        Table = [First, Last, Snack, Seasoning],
    
        First = [Arthur, Frank, Jake, Paul, Stan],
        Last  = [Bradley, Jones, Manor, Night, Summer],
        Snack = [Swordfish, Potato, Pork, Chicken, Lasagna],
        Seasoning = [Basil, Cinnamon, Paprika, Sage, Spearmint],
    
        First = [1, 2, 3, 4, 5],
    
        maplist(all_distinct, Table),
        append(Table, Vs),
        Vs ins 1..5,
    
        pairs_keys_values(PFirst, First, [arthur, frank, jake, paul, stan]),
        pairs_keys_values(PLast, Last, [bradley, jones, manor, night, summer]),
        pairs_keys_values(PNames, PFirst, PLast),
        pairs_keys_values(PSnack, Snack, [swordfish, potato, pork, chicken, lasagna]),
        pairs_keys_values(PNameSnack, PNames, PSnack),
        pairs_keys_values(PSeasoning, Seasoning, [basil, cinnamon, paprika, sage, spearmint]),
        pairs_keys_values(Pairs, PNameSnack, PSeasoning),
    
        Paprika #= Lasagna,
        Paprika #\= Arthur,
        Stan #\= Night,
        Stan #\= Spearmint,
        Bradley #= Cinnamon,
        Jake #\= Manor,
        Jake #= Basil,
        Jake #\= Swordfish,
        Paul #= Potato,
        Paul #\= Spearmint,
        Arthur #\= Night,
        Frank #= Jones,
        Frank #\= Swordfish,
        Stan #\= Manor,
        Stan #= Pork,
        Stan #\= Sage,
        Summer #\= Arthur,
        Summer #= Chicken,
        Summer #\= Sage.
    

    Which gives:

    ?- solve(Pairs).
    
    Pairs = [
    1-arthur-(5-bradley)-(1-swordfish)-(3-basil), 
    2-frank-(2-jones)-(4-potato)-(5-cinnamon),
    3-jake-(1-manor)-(5-pork)-(2-paprika),
    4-paul-(4-night)-(3-chicken)-(4-sage),
    5-stan-(3-summer)-(2-lasagna)-(1-spearmint)]
    

    (A single solution found by constraint propagation, no search).