prologzebra-puzzle

Zebra puzzle - who lives on which floor?


I have a zebra/Einstein type Prolog puzzle very similar to the one depicted here:

A "Building" Riddle in Prolog.

The riddle is:

There are two buildings, each one has tree apartments (one apartment on each floor): one apartment of 3 rooms, one of 4 rooms and one of 5 rooms.

Dana, Joni and Noah live in building 1. Ron, Gale and Aron live in building 2.

Joni's apartment is higher then Dana's and Noah's. It means he lives on the third floor of building 1. Noah and Gale live on the same floor (in different buildings). Ron has one more room than Aron. Ron lives one floor above Gale. The highest apartment in building 2 is the 5 rooms apartment.

I need to find in which floor everyone lives.

This is the code.

solve([dana,building1,F1,R1],
      [noah,building1,F2,R2],
      [joni,building1,F3,R3],
      [gale,building2,F4,R4],
      [ron, building2,F5,R5],
      [aron,building2,F6,R6]) :-
   assign([1,2,3],[F1,F2,F3]),
   assign([1,2,3],[F4,F5,F6]),
   assign([3,4,5],[R1,R2,R3]),
   assign([3,4,5],[R4,R5,R6]),
   F3 > F2,
   F3 > F1,
   F2 =:= F4,
   R5 =:= R6-1,
   F5 =:= F4+1,
   (  F4 =:= 3, R4 =:= 5
   ;  F5 =:= 3, R5 =:= 5
   ;  F6 =:= 3, R6 =:= 5
   ).

assign(_,[]).
assign(Digs,[D|Vars]):-
   del(D,Digs,Digs1),
   assign(Digs1,Vars).

del(X,L,L1) :-
   remove(X,L,L1).

remove([],X,[]) :- !. 
remove([X|T],X,L1) :- !, remove(T,X,L1).   
remove([H|T],X,[H|L1]) :- remove(T,X,L1).

I don't understand which query to use with this following solution? When I try the query from the original post,

solve([dana,building1,F1,R1],[noah,building1,F2,R2],[joni,building1,F3,R3],
      [gale,building2,F4,R4],[ron, building2,F5,R5],[aron,building2,F6,R6]).

it says

Type error: `evaluable' expected, found `[]' (an empty_list)
In:
   [2] []>[]
   [1] solve([dana,building1|...],[noah,building1|...],[joni,building1|...],
             [gale,building2|...],[ron, building2|...],[aron,building2|...]) 
at  line 1

What is the correct query for this?

Thanks.


Solution

  • The query is correct for the given code.

    The code contains an error.

    del(X,L,L1) :-
       remove(X,L,L1).   % WRONG
    

    You need to change the order of arguments in the call to remove/3, to correspond to their use in the definition of remove/3.

    You could discover it by testing in the small. Just trying the query assign([1,2,3],Floors) at the prompt, you'd discover whether it works as intended or not.

    Or del(D,[1,2,3],Digs1), following the assign/2 definition,

    assign([1,2,3],[D|Vars]):-
       del(D,[1,2,3],Digs1),
       ..... .

    Or remove(D,[1,2,3],Digs1), following the del/3 definition,

    del(D,[1,2,3],Digs1) :-
       remove(D,[1,2,3],Digs1).

    Looking at the definition

    remove([],   X,[]    ) :- !. 
    remove([X|T],X,L1    ) :- !, remove(T,X,L1).
    remove([H|T],X,[H|L1]) :- remove(T,X,L1).

    knowing that our intended meaning for D is to hold one digit from among [1,2,3],

    (the rest is intentionally left blank)