无法在Prolog中为防盗拼图建模

时间:2019-04-28 15:47:39

标签: prolog

我正在为此simple logic puzzle建模:

  

三个人中只有一个,爱丽丝(Alice),贝托(Beto)和卡尔(Carl)偷了Doubtfire女士的钱。她雇用您担任顾问侦探。在对它们进行讯问之后,您将拥有以下内容:

     

爱丽丝:不要相信卡尔。他在撒谎,他拿了钱。

     

卡尔:贝托在撒谎,但爱丽丝没有拿钱。

     

贝托:卡尔拿了钱。我没有拿钱。

     

收集信息后,您知道,只要其中一个说谎,他们就会对陈述的两个部分都撒谎。同样,如果其中一个人讲真话,他们在陈述的两个部分都讲真话。谁拿了钱?

我以与this video about Knights and Knaves类似的方式对其进行建模。特别是,我使用11:34附近的“基于Prolog”解决方案,而不是之前介绍的基于SAT解算器的模型进行建模。我对false关系做了一些修改。

says(guilty_liar, S) :- not(S).
says(innocent_liar, S) :- not(S).
says(guilty_but_honest, S) :- S.
says(innocent_and_honest, S) :- S.

false(A = guilty_liar) :- A = innocent_and_honest.
false(A = guilty_but_honest) :- A = innocent_liar.
false(A = innocent_liar) :- A = guilty_but_honest.
false(A = innocent_and_honest) :- A = guilty_liar.
false((P ; Q)) :- false(P), false(Q) .
false((P , Q)) :- ( false(P) ; false(Q) ).

然后,我将进行以下查询:

?- [burglar].
  true.

?- says(A, (C = guilty_liar)), says(C, ((B = guilty_liar ; B = innocent_liar), (A = innocent_liar ; A = innocent_and_honest ))), says(B, ((C = guilty_liar ; C = guilty_but_honest) , (B = innocent_and_honest ; B = innocent_liar))).
    A = guilty_but_honest,
    C = B, B = guilty_liar ;
    A = guilty_but_honest,
    C = guilty_liar,
    B = innocent_and_honest ;
  false.

尽管我期望的不仅仅是正确的解决方案(因为我没有放下所有限制条件),但是我期望正确的解决方案会出现。也就是说,爱丽丝天真无邪,但撒谎,卡尔讲真话,贝托是有罪的骗子。

此外,这是第二条查询,分为多行,以方便阅读:

says(A, (C = guilty_liar)),
says(C, ((B = guilty_liar ; B = innocent_liar), (A = innocent_liar ; A = innocent_and_honest ))),
says(B, ((C = guilty_liar ; C = guilty_but_honest) , (B = innocent_and_honest ; B = innocent_liar))).

我很困惑为什么没有显示正确的解决方案。


更新

我愚蠢地使用了not而不是我定义的false函数,但是,即使用not(S)退出false(S)也会得到false.的查询

2 个答案:

答案 0 :(得分:1)

我是这样做的:

?- People = [alice(_, _), beto(_, _), carl(_, _)], alice(People), carl(People), beto(People), write(People), nl, fail.

alice(People) :-
    member(alice(honest, innocent), People),
    member(carl(liar, thief), People).

alice(People) :-
    member(alice(liar, _), People),
    member(carl(honest, innocent), People).

carl(People) :-
    member(carl(honest, _), People),
    member(beto(liar, _), People),
    member(alice(_, innocent), People).

carl(People) :-
    member(carl(liar, _), People),
    member(beto(honest, _), People),
    member(alice(_, thief), People).

beto(People) :-
    member(beto(honest, innocent), People),
    member(carl(_, thief), People).

beto(People) :-
    member(beto(liar, thief), People),
    member(carl(_, innocent), People).

结果[alice(liar, innocent), beto(liar, thief), carl(honest, innocent)]


这稍微简单一些:

alice([alice(honest, innocent), beto(_, _), carl(liar, thief)]).        
alice([alice(liar, _), beto(_, _), carl(honest, innocent)]).
carl([alice(_, innocent), beto(liar, _), carl(honest, _)]).     
carl([alice(_, thief), beto(honest, _), carl(liar, _)]).
beto([alice(_, _), beto(honest, innocent), carl(_, thief)]).
beto([alice(_, _), beto(liar, thief), carl(_, innocent)]).

答案 1 :(得分:1)

这对我来说似乎非常可疑:says(A, (C = guilty_liar))。 可能存在一个约束,即两个语句都为true或均为false,因此这里只有一个语句。您认为您的逻辑能够正确处理此问题?

无论如何,这是我天真的解决方案:-)为每个命题创建一个true / false变量,并表达这些变量的有效值的所有约束。

true_or_false(X) :- X = true.
true_or_false(X) :- X = false.

bool_to_int(true, 1).
bool_to_int(false, 0).

true_or_false_list([]).
true_or_false_list([V | T]) :- true_or_false(V), true_or_false_list(T).

solution(AliceCorrect, CarlCorrect, BetoCorrect,
         AliceThief, CarlThief, BetoThief) :-
  true_or_false_list([AliceCorrect, CarlCorrect, BetoCorrect,
                      AliceThief, CarlThief, BetoThief]),
  % Alice statement.
  AliceCorrect \= CarlCorrect,
  AliceCorrect = CarlThief,
  % Carl statement.
  CarlCorrect \= BetoCorrect,
  CarlCorrect \= AliceThief,
  % Beto Statement.
  BetoCorrect = CarlThief,
  BetoCorrect \= BetoThief,
  % There can be only one thief.
  bool_to_int(AliceThief, AliceThiefInt),
  bool_to_int(CarlThief, CarlThiefInt),
  bool_to_int(BetoThief, BetoThiefInt),
  1 is AliceThiefInt + CarlThiefInt + BetoThiefInt.

贝托是个小偷。