prologzebra-puzzle

Prolog Logic Puzzle Failure


I am attempting to solve the logic puzzle found here: https://www.braingle.com/brainteasers/teaser.php?id=23826&op=2&comm=1#c

These are the clues:

  1. The flowers were purchased in the following order: tulips, the flowers for the office, the purple flowers, the roses for the park, and the white flowers bought by Julia.

  2. Bethany loves flowers but is allergic, so she would never have them indoors.

  3. It rained on Wednesday and Friday, because of this, the wedding and birthday party had to be moved indoors.

  4. Amy bought her flowers after Rachel, but before Kristen.

  5. Rachel needed something more to add to her office, so she chose peach flowers to match her curtains.

  6. On Wednesday the only purple flowers available at the flower shop were daisies.

  7. The pink flowers were bought after the carnations, but before the lilies.

  8. The flowers for the birthday were bought after the flowers for the office, but before the flowers for the wedding.

I have attempted to implement this in prolog with the following code:

/*
Use a nested predicate of flowers to store the solution

flowers(
  f(Woman1,Flower1,Color1,Place1,Day1),
  f(Woman2,Flower2,Color2,Place2,Day2),
  f(Woman3,Flower3,Color3,Place3,Day3),
  f(Woman4,Flower4,Color4,Place4,Day4),
  f(Woman5,Flower5,Color5,Place5,Day5)
).
*/

/* The flowers predicate contains a given flower X */
has(X,F) :- F=flowers(X,_,_,_,_).
has(X,F) :- F=flowers(_,X,_,_,_).
has(X,F) :- F=flowers(_,_,X,_,_).
has(X,F) :- F=flowers(_,_,_,X,_).
has(X,F) :- F=flowers(_,_,_,_,X).

/*Defines that X occurs on an earlier day than Y */
before(X,Y,F) :- append(_,[X|Tail], F), append(_,[Y|_],Tail).


solve(F) :-
  F = flowers(A,B,C,D,E),
/*clue 1 */
  A = f(_,tulips,yellow,_,monday),
  B = f(_,_,_,office,tuesday),
  C = f(_,_,purple,_,wednesday),
  D = f(_,roses,_,park,thursday),
  E = f(julia,_,white,_,friday),
/* Clue 2 --> Look @ clue 3, Bethany can only have flowers in backyard or park */
  has(f(bethany,_,_,backyard,_),F), 
  has(f(bethany,_,_,_,park,_),F),
/* Clue #4, Amy before Kristen, Rachel before Amy */
  before(f(amy,_,_,_,_),f(kristen,_,_,_,_),F),
  before(f(rachel,_,_,_,_),f(amy,_,_,_,_),F),
/* Clue #5 */
  has(f(rachel,_,peach,office,_),F),
/* Clue #6 */
  has(f(_,daisies,purple,_,wednesday),F),
/* Clue #7, pink before lillies, carnations before pink */
  before(f(_,_,pink,_,_),f(_,lilies,_,_,_),F),
  before(f(_,carnations,_,_,_),f(_,_,pink,_,_),F),
/* Clue #8 */
  before(f(_,_,_,birthday,_),f(_,_,_,wedding,_),F),
  before(f(_,_,_,office,_),f(_,_,_,birthday,_),F).

This doesn't seem to be working. I believe the problem is either with my code in defining a flower occurs before another one, but I am not sure if that is the issue and how to remedy it. Also, I think there's an issue with saying that Bethany bought flowers for backyard or park (NOT wedding, bday, or office).

Here is the answer to the puzzle:

Julia: Lilies, White, Wedding, Friday

Amy: Daisies, Purple, Birthday, Wednesday

Bethany: Tulips, Yellow, Backyard, Monday

Rachel: Carnations, Peach, Office, Tuesday

Kristen: Roses, Pink, Park, Thursday


Solution

  • You before/3 predicate was trying to deal with flowers(A,B,C,D,E) as if it were a list. It was always failing. You would need to define it as [A,B,C,D,E] for it to work.

    It's actually better if you change flowers(A,B,C,D,E) to [A,B,C,D,E] so that you can use the built-in predicate member/2 instead of has/2.

    So, to start with I did this:

    writeln(X) :- write(X), nl.
    
    writelist([]).
    writelist([H|T]) :- writeln(H), writelist(T).
    
    /*Defines that X occurs on an earlier day than Y */
    before(X,Y,F) :- append(F0, F1, F), member(X, F0), member(Y, F1).
    

    You were also trying to say that bethany in in the backyard and the park. It needed to be an or relation.

    Here's my version of solve/1:

    solve(F) :-
    /*clue 1 */
        F = [
            f(_,tulips,yellow,_,monday),
            f(_,_,_,office,tuesday),
            f(_,_,purple,_,wednesday),
            f(_,roses,_,park,thursday),
            f(julia,_,white,_,friday)
        ],
    /* Clue 2 --> Look @ clue 3, Bethany can only have flowers in backyard or park */
        (member(f(bethany,_,_,backyard,_),F);
            member(f(bethany,_,_,_,park,_),F)),
    /* Clue #4, Amy before Kristen, Rachel before Amy */
        before(f(amy,_,_,_,_),f(kristen,_,_,_,_),F),
        before(f(rachel,_,_,_,_),f(amy,_,_,_,_),F),
    /* Clue #5 */
        member(f(rachel,_,peach,office,_),F),
    /* Clue #6 */
        member(f(_,daisies,purple,_,wednesday),F),
    /* Clue #7, pink before lillies, carnations before pink */
        before(f(_,_,pink,_,_),f(_,lilies,_,_,_),F),
        before(f(_,carnations,_,_,_),f(_,_,pink,_,_),F),
    /* Clue #8 */
        before(f(_,_,_,birthday,_),f(_,_,_,wedding,_),F),
        before(f(_,_,_,office,_),f(_,_,_,birthday,_),F),
        true.
    

    Now when I query ?- solve(F), writelist(F). I get this:

    f(bethany, tulips, yellow, backyard, monday)
    f(rachel, carnations, peach, office, tuesday)
    f(amy, daisies, purple, birthday, wednesday)
    f(kristen, roses, pink, park, thursday)
    f(julia, lilies, white, wedding, friday)
    Yes.