Einsteins puzzle in prolog

624 Views Asked by At

I have tried to solve the Einstein puzzle - five friend edition - in prolog, but Im stuck. I can't seem to find the error in my code, or what to do to solve it. The goal is to write a Prolog program that identifies correctly what kind of puzzle each of them did, the theme of the puzzle and how long it took them to complete it - solution(Person, Kind, Time, Theme)

I also get this error: uncaught exception: error(existence_error(procedure,members/3),clue1/0)

I think it something to do with members?

the knowledge base:

  1. The five friends are Krystal, Angie, the one who did the Outerspace puzzle, the one who took 30 minutes to complete the puzzle, and the one who did the Word Search.

  2. Ethan either finished the letter tiles in 90 minutes or did the winter themed puzzle in 20 minutes.

  3. Of Dereck and the one who did the Logic Puzzle, one took 45 minutes while the other did a movies themed puzzle. Boys took the shortest and longest times to finish their puzzles.

  4. Nick spent less than 40 minutes working on his puzzle, which was not the Visual Sudoku. Angie spent more than 40 minutes working on her Cat puzzle.

  5. The girl who spent 60 minutes working on a sports puzzle did NOT do the Jigsaw. the jigsaw was done by a boy in less time than the one who did the Logic Puzzle but more time than the one who did the Word Search.

  6. The Visual Sudoku either took an hour to complete or was Outerspace themed. Dereck did not do the winter themed puzzle (which was not the Word Search.)

Here is my code:

woman(krystal).
woman(angie).
man(dereck).
man(ethan).
man(nick).

kind(word).
kind(sudoku).
kind(letter).
kind(jigsaw).
kind(logic).

time(30).
time(90).
time(20).
time(45).
time(60).

theme(outerspace).
theme(winter).
theme(movies).
theme(sports).
theme(cat).

members([],_).
members([M|Ms],Xs) :- select(M,Xs,Ys),members(Ms,Ys).


clue1(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_], [P,word,_,_], [P,_,_,outerspace]], Game, man(P)).
clue2(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,_,outerspace], [P,_,_,outerspace], [P,_,_,outerspace]], Game, man(P)).
clue3(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,30,_], [P,_,30,_], [P,_,30,_]], Game, man(P)).
clue4(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,_,word], [P,_,_,word], [P,_,_,word]], Game, man(P)).
clue5(Game) :- member([ethan, letter, 90,_], Game).
clue5(Game) :- member([ethan, _, 20, winter], Game).
clue6(Game) :- member([P, _, 20, _], Game, man(P)).
clue6(Game) :- member([P, _, 90, _], Game), man(P).
clue7(Game) :- member([dereck, _, 45, _], Game).
clue7(Game) :- member([dereck, _, _, movies], Game).
clue8(Game) :- member([_, logic, 45, _], Game).
clue8(Game) :- member([_, logic, _, sport], Game).
clue9(Game) :- member([nick, _, 30, _], Game).
clue9(Game) :- member([nick, _, 20, _], Game).
clue10(Game) :- member([P, sudoku, _, _], Game, \+nick(P)).
clue11(Game) :- member([angie, _, 45, cat], Game).
clue11(Game) :- member([angie, _, 60, cat], Game).
clue11(Game) :- member([angie, _, 90, cat], Game).
clue12(Game) :- member([P, Q, 60, sport], Game, girl(P), \+sport(Q)).

clue13(Game) :- member([P, jigsaw, Q, _], Game, man(P), \+time(20)).
clue13(Game) :- member([P, jigsaw, Q, _], Game, man(P), \+time(90)).
clue13(Game) :- member([P, jigsaw, 30, _], Game, man(P)), member([_, word, 20, _], Game), (member([_, logic, 40, _], Game); member([_, logic, 60, _], Game); member([_, logic, 90, _], Game)).
clue13(Game) :- member([P, jigsaw, 45, _], Game, man(P)), (member([_, word, 20, _], Game); member([_, word, 30, _], Game)), (member([_, logic, 60, _], Game); member([_, logic, 90, _], Game)).
clue13(Game) :- member([P, jigsaw, 60, _], Game, man(P)), (member([_, word, 20, _], Game); member([_, word, 30, _], Game); member([_, word, 46, _], Game)), member([_, logic, 90, _], Game).

clue14(Game) :- member([_, sudoku, 60, _], Game).
clue14(Game) :- member([_, sudoku, _, outerspace], Game).
clue15(Game) :- member([P, _, _, winter], Game, \+dereck(P)).
clue16(Game) :- member([_,word,_,P], Game, \+winter(P)).

clue17(Game, A,B,C,D) :- member([A,B,C,D], Game).

solution(A,B,C,D) :-
    Game = [A,B,C,D],
    clue1(Game),
    clue2(Game),
    clue3(Game),
    clue4(Game),
    clue5(Game),
    clue6(Game),
    clue7(Game),
    clue8(Game),
    clue9(Game),
    clue10(Game),
    clue11(Game),
    clue12(Game),
    clue13(Game),
    clue14(Game),
    clue15(Game),
    clue16(Game),
    clue17(Game, A,B,C,D),
    members([[_,sudoku,_,_], [_,logic,_,_],[_,letter,_,_],[_,jigsaw,_,_],[_,word,_,_]],Game),
    members([[krystal,_,_,_],[angie,_,_,_],[ethan,_,_,_],[dereck,_,_,_],[nick,_,_,_]],Game),
    members([[_,_,60,_],[_,_,45,_],[_,_,90,_],[_,_,30,_],[_,_,20,_]],Game),
    members([[_,_,_,sports],[_,_,_,cat],[_,_,_,outerspace],[_,_,_,movies],[_,_,_,winter]],Game),
    write(Game),
    true.

/*
1) One is named Krytal who didnt do the Outerspace puzzle, the Word search and didnt use 30 min 
    and One is named Angie who didnt do the Outerspace puzzle, the Word search and didnt use 30 min
2) One boy did the Outerspace puzzle
3) One boy used 30 min
4) One boy did the Word Search  
5) Ethan either finished the letter tiles in 90 minutes or did the winter themed puzzle in 20 minutes.
6) Boys took the shortest and longest times to finish their puzzles.
7) Dereck either took 45 minutes or did a movies themed puzzle.
8) The one who did the logic puzzle either took 45 minutes or did a movies themed puzzle.
9) Nick spent less than 40 minutes working on his puzzle
10) Nick did not the Visual Sudoku. 
11) Angie spent more than 40 minutes working on her Cat puzzle.
12) The girl who spent 60 minutes working on a sports puzzle did NOT do the Jigsaw. 
13) the jigsaw was done by a boy in less time than the one who did the Logic Puzzle but more time than the one who did the Word Search.
14) The Visual Sudoku either took an hour to complete or was Outerspace themed. 
15) Dereck did not do the winter themed puzzle 
16) The Word Search is not winter themed
*/
1

There are 1 best solutions below

0
On

This is only an answer to the most immediate question, it will not give you a complete working solution. Still, you are on a good path, please don't be discouraged!

Also, first of all: Loading your program into SWI-Prolog gives two warnings:

Warning: /home/isabelle/einstein.pl:49:
    Singleton variables: [Q]
Warning: /home/isabelle/einstein.pl:50:
    Singleton variables: [Q]

This means that in the clauses at these locations you have "singleton" variables: Variables that only occur once in the clause. Singleton variables can indicate very serious logic bugs, so you should not ignore such warnings. Maybe the variable Q in the first two clauses of clue13 should somehow relate to the times 20 and 90?

As for your error message, let's unpack it:

  • existence_error(procedure, ...) means that you were trying to call a "procedure" (more typically we call them "predicates") that doesn't exist
  • members/3 is the procedure that doesn't exist
  • clue1/0 is the location of the bad call.

For reference, my local version of SWI-Prolog reports the same error like this, which is a bit more user friendly:

?- solution(A, B, C, D).
ERROR: Undefined procedure: members/3
ERROR:   However, there are definitions for:
ERROR:         members/2
ERROR: 
ERROR: In:
ERROR:   [10] members([[krystal|...],...|...],[_3044,_3050|...],man(_3056))
ERROR:    [9] clue1([_3084,_3090|...]) at /home/isabelle/einstein.pl:29
ERROR:    [8] solution(_3116,_3118,_3120,_3122) at /home/isabelle/einstein.pl:64
ERROR:    [7] <user>

Either way, you are trying to call, from clue1, a predicate members with three arguments, but no such definition exists. Let's look at your definition:

clue1(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_], [P,word,_,_], [P,_,_,outerspace]], Game, man(P)).

The problem is hard to spot because you learned very bad code formatting habits. This is not your fault: Way too many classic Prolog books insist on putting way too much code on one line, so way too many Prolog programmers write their code that way.

What you meant was something more like this:

clue1(Game) :-
    members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_],
             [P,word,_,_], [P,_,_,outerspace]],
            Game,
    man(P)).

Can you see it now? The members call should be closed after Game, and man(P) should not be an argument to this call. So this should be:

clue1(Game) :-
    members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_],
             [P,word,_,_], [P,_,_,outerspace]],
            Game),
    man(P).

I very very strongly recommend that you don't write more than one goal per line, and to break long lines inside of goals as well. You will need to fix a few more predicates in a similar way.

After this, your program will no longer have the existence error but quickly fail inside the members call. You are trying to call members(<five-element list>, <four-element list>), and this cannot succeed. The way you set up the Game variable inside solution looks wrong. Try using much much more descriptive names than A to D for the objects you are talking about.