/*
Smullyan's Knights and Knaves problems in Picat.
Here are the problems 26 to 34 from Raymond Smullyan's wonderful book
"What is the name of this book? - The riddle of dracula and
other logical puzzles".
This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com
See also my Picat page: http://www.hakank.org/picat/
*/
import cp.
main => go.
%
% This is the basic approach.
%
% Problem 26:
% B: A says he is a knave
% C: B is a knave
% What are B and C?
% Solution: A: unknown, B: knave, C: knight
go =>
knight_knave(3,_Knight,Knave,P),
% B: A says he is a knave
(P[2] #= (P[1] #= (P[1] #= Knave))),
% says(P[2], $says(P[1], P[1] #= Knave)),
% C: B is a knave
(P[3] #= (P[2] #= Knave)),
% says(P[3], P[2] #= Knave),
solve(P),
println(translate(P)),
nl.
% more general version
go2 =>
Problems = [p26,p26b,p27,p28,p29,p30,p31,p32,p33,p34],
foreach(Problem in Problems)
printf("Problem %w:\n", Problem),
problem(Problem,Ss,P),
foreach(S in Ss)
println(S)
end,
((smullyan(Ss,P), fail) ; true),
nl
end.
%
% smullyan(Statements,People)
%
smullyan(Statements,P) =>
foreach(S in Statements)
call(S)
end,
solve(P),
println(translate(P)).
translate(P) = [cond(K=1,knight,knave) : K in P].
% Two different uses of says/2:
% - as a predicate
% - as a "structure" which is first unravelled
says(Kind, Says) =>
if Says = $says(Kind2,Says2) then
Kind #= (Kind2 #= Says2)
else
Kind #= (Says)
end.
% - knights always tells the truth (1)
% - knave always lies (0)
knight_knave(N, Knight,Knave,P) =>
Knight = 1,
Knave=0,
P = new_list(N),
P :: 0..1.
%
% Problems
%
% Problem 26:
% B: A says he is a knave
% C: B is a knave
% What are B and C?
% Solution: A: unknown, B: knave, C: knight
problem(p26,S,P) =>
knight_knave(3,_Knight,Knave,P),
S = $[
says(P[2], $says(P[1], P[1] #= Knave)), % B: A says he is a knave
says(P[3], P[2] #= Knave) % C: B is a knave
].
% Variant of problem 26, commented in problem 27, we don't need
% C to know that B is a knave.
% B: A says he is a knave
% What are B?
% Solutution: A: unknown, B is a knave
problem(p26b,S,P) =>
knight_knave(2,_Knight,Knave,P),
S = $[
says(P[2], $says(P[1], P[1] #= Knave)) % B: A says he is a knave
].
% Problem 27
% B: A said that there are exactly 1 knights
% C: B is a knave
% What are B and C
% Solution: B: knave, C: knight
problem(p27,S,P) =>
knight_knave(3,_Knight,Knave,P),
S = $[
says(P[2], $says(P[1], sum(P) #= 1)), % B: A said that there are exactly 1 knights
says(P[3], P[2] #= Knave) % C: C: B is a knave
].
% Problem 28
% Just a and b (sets c = 1)
% A: at least one of us is a knave
% Solution: A: knight, B: knave
problem(p28,S,P) =>
knight_knave(2,_Knight,Knave,P),
S = $[
says(P[1], sum([P[I] #=Knave : I in 1..2]) #>= 1) % A: at least one of us is a knave
].
% Problem 29
% A: either A is a knave or B is a knight
% Solution: A: knight, B: knight
problem(p29,S,P) =>
knight_knave(2,Knight,Knave,P),
S = $[
says(P[1], P[1] #= Knave #\/ P[2] #= Knight) % A: either A is a knave or B is a knight
].
% Problem 30
% A: either A is a knave or 2 + 2 = 5
% Solution: Infeasible.
problem(p30,S,P) =>
knight_knave(1,_Knight,Knave,P),
S = $[
says(P[1], P[1] #= Knave #\/ 2 + 2 #= 5) % A: either A is a knave or 2 + 2 = 5
].
% Problem 31
% A: All are knaves
% B: Exactly one is a knight
% Solution: A: knave, B: knight, C: knave
problem(p31,S,P) =>
knight_knave(3,Knight,Knave,P),
S = $[
says(P[1], sum([K #= Knave : K in P]) #= 3), % A: All are knaves
says(P[2], sum([K #= Knight :K in P]) #= 1) % B: Exactly one is a knight
].
% Problem 32
% A: all are knaves
% B: exactly one is a knave
% Solution: A: knave, B: knight or knave, C: knight
problem(p32,S,P) =>
knight_knave(3,_Knight,Knave,P),
S = $[
says(P[1], sum([K #= Knave : K in P]) #= 3), % A: all are knaves
says(P[2], sum([K #= Knave : K in P]) #= 1) % B: exactly one is a knave
].
% Problem 33
% A: A is knave, B is knight.
% Solutions: A: knave, B: knave
problem(p33,S,P) =>
knight_knave(2,Knight,Knave,P),
S = $[
says(P[1], P[1] #= Knave #/\ P[2] #= Knight) % A: A is knave, B is knight.
].
% Problem 34
% A: B is a knave
% B: A and C is of the same type
% Solution: A and B is not of the same type, C: knave
problem(p34,S,P) =>
knight_knave(3,_Knight,Knave,P),
S = $[
says(P[1], P[2] #= Knave), % A: B is a knave
says(P[2], P[1] #= P[3]) % B: A and C is of the same type
].