[英]Simple Knights and Knaves Problem in SWI-Prolog
我正在嘗試使用針對N
個人的生成和測試方法解決“Knights and Knaves”問題,以便我可以實現以下結果:
?- find_knaves([3,2,1,4,2], Knaves).
Knaves = [1,0,0,1,0]
以上結果可以解釋如下:
X
是knaves” , X
是第一個列表中對應每個人的數字。 Knaves
列表中用1
表示的人被證明是knaves。 我的方法:
我的想法是創建包含0
和1
的Knaves
列表的所有排列,然后過濾掉那些不符合人們聲明的那些:
evaluate([], _).
evaluate([Head|Tail], List) :-
member(Head, List),
evaluate(Tail, List).
permute(Number, List, Permutations) :-
length(Permutations, Number),
evaluate(Permutations, List).
find_knaves(Statements, Results) :-
length(Statements, FriendsNumber),
permute(FriendsNumber, [0, 1], Results).
上面的代碼創建了所有的排列,但現在我不知道如何繼續保持只有一個正確的排列。
我確定必須有一個遞歸,我必須查看Statements
列表,但后來我不確定條件應該是什么。 我正在考慮以下幾行(偽代碼):
check([Head|Tail], Results) :-
% Condition:
% Head three or more times in the Results
check(Tail, Results).
我的方法是朝着正確的方向前進嗎? 如果沒有,解決這個問題的最佳方法是什么?
這是對您的解決方案的最小補充(稍微重命名為一些謂詞):
enumerate_n(N, Symbols, R) :-
length(R, N),
enumerate_n(R, Symbols).
enumerate_n([], _).
enumerate_n([X|Xs], Symbols) :-
member(X, Symbols),
enumerate_n(Xs, Symbols).
check_statements(Statements, Solution) :-
length(Statements, N),
enumerate_n(N, [0,1], Solution),
include(==(1), Solution, Knaves),
length(Knaves, N_knaves),
maplist(validate(N_knaves), Statements, Solution).
validate(Knaves, Statement, 0) :-
Statement =< Knaves.
validate(Knaves, Statement, 1) :-
Statement > Knaves.
它可以解決你的例子:
?- check_statements([3,2,1,4,2], S).
S = [1, 0, 0, 1, 0] ;
false.
它報告說沒有更多的解決方案。
編輯:你可以有點聰明,並通過總結列表計算knaves。
代替:
include(==(1), Solution, Knaves),
length(Knaves, N_knaves)
你可以寫:
sum_list(Solution, N_knaves)
您可以使用same_length/2
而不是length/2
。 您還可以使用maplist
替換遞歸謂詞。 代碼變成:
statements_knaves(S, K) :-
same_length(S, K),
maplist(knave, K),
sum_list(K, N),
maplist(validate(N), S, K, _).
knave(0).
knave(1).
validate(N, X, 0, knight) :- X =< N.
validate(N, X, 1, knave) :- X > N.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.