Search code examples
prologclpb

Unknown procedure card/2 in knights and knaves puzzle


I'm programming some knight and knaves puzzles using both sat/1 and a more natural language approach using the custom propositions A says B and false().

Question 3 is stated as follows:

You meet three inhabitants, A, B and C.

A says: "All three of us are knaves".

B says: "Exactly one of us is a knight".

However, in my solutions that use custom propositions for some reason prolog is giving me Unknown procedure card/2. Here's the code (see question3_again proposition).


question3(A,B,C):- sat(A =:= card([0],[A,B,C])), sat(B =:= card([1],[A,B,C])).

% Now let's make it more intuitive to work with prolog by creating our own operator:

:- op(900,xfy,says).

knight says S :- S.
knave  says S :- false(S).

false(A = B) :- dif(A,B).
false( (A ; B) ) :- false(A), false(B).
false( (A , B) ) :- false(A); false(B).

question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
                         B says ( card( [1], [A = knight, B = knight, C = knight] ) ).

I tried counting the number of knights and using this solution below instead, but it gives me incorrect answers( I added false(A #= B) :- A #\= B. so false could reason about integers):

false(A #= B) :- A #\= B.

counte(_,[],Count,Count).
counte(E,[H|T],C,Count) :- (E = H, CC is C+1 ; CC is C), counte(E,T,CC,Count).
counte(E,L,Count) :- counte(E,L,0,Count).

question3_again(A,B,C) :- counte(knight,[A,B,C],Knights),
                          A says ( Knights #= 0 ),
                          B says ( Knights #= 1 ).

Can someone give me a light?

Thank you in advance!


Solution

  • question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
                              B says (permutation([A, B, C], [knave, knave, knight])).
    
    ?- question3_again(A, B, C).
    A = C, C = knave,
    B = knight
    

    With permutation you will get same solution multiple times. If you want to, you can avoid that with some thing like:

    one_knight(X) :- nth0(_, X, knight, [knave, knave]).
    
    ?- one_knight(X).
    X = [knight, knave, knave] ;
    X = [knave, knight, knave] ;
    X = [knave, knave, knight] ;
    false.
    

    permutation would have given 6 choices.

    Now your solution will be:

    question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
                              B says (one_knight([A, B, C])).