2

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!

false
  • 10,264
  • 13
  • 101
  • 209
Luiz
  • 99
  • 5
  • Are you using `swi-prolog`? If so, add that tag too. – rajashekar Oct 13 '21 at 14:31
  • @rajashekar I did add the ```swi-prolog``` tag, but for some reason the tag disappeared. Oh well, now it's working :) – Luiz Oct 13 '21 at 14:35
  • 1
    `card/2` is a boolean expression, not a prolog predicate. You cannot use it outside a `clpb` context(eg., `sat`, `taut` etc...). – rajashekar Oct 13 '21 at 14:39
  • `knight says S :- S.` implies that the predicate `S` must succeed. And hence`B says card(...)` triggers that rule. Since `card` is not a predicate you have an error. – rajashekar Oct 13 '21 at 14:44
  • Ohh I see, I wasn't aware of that fact! Can anyone help me to make question3_again work as intended? I couldn't find a fitting substitution for card in question3_again, as you can see, my version that counts the number of knights doesn't work :S – Luiz Oct 13 '21 at 14:50
  • `I did add the swi-prolog tag, but for some reason the tag disappeared` It is not you. One of the users here is prodigious about removing that tag if the question can only work with SWI-Prolog. – Guy Coder Oct 13 '21 at 16:32
  • @GuyCoder Oh, I see :) Well, let's hope the ```swi-prolog``` tag stays there for good this time! – Luiz Oct 13 '21 at 21:14
  • @Luiz: There is nothing SWI-specific in your question. Any system equipped with `clpb` (and clpfd) will do. – false Oct 14 '21 at 15:39

1 Answers1

2
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])).
rajashekar
  • 3,460
  • 11
  • 27
  • Wow, perfect solution! Thank you very much for your help! – Luiz Oct 13 '21 at 14:57
  • I saw you added the one_knight solution that's even better, now my queries won't come up with duplicates :P Thank you! – Luiz Oct 13 '21 at 15:14