简体   繁体   English

使用Prolog解决逻辑难题

[英]Solving a logic puzzle using Prolog

The criminal is one of A, B, C and D. 罪犯是A,B,C和D之一。

A says: "It's not me" A说:“不是我”
B says: "It's D" B说:“是D”
C says: "It's B" C说:“是B”
D says: "It's not me" D说:“不是我”

And we know that only one of them tells the truth. 我们知道,只有其中一个说实话。

Who is the one? 谁是那个? I want to solve it by using Prolog. 我想使用Prolog解决它。

It's an interview question. 这是一个面试问题。

One-liner solution 一线解决方案

?- member(K,[a,b,c,d]),(K\=a->A=1;A=0),(K=d->B=1;B=0),(K=b->C=1;C=0),(K\=d->D=1;D=0),A+B+C+D=:=1.
K = a,
A = 0,
B = 0,
C = 0,
D = 1 ;
false.

Disclaimer : This is Xonix ' solution. 免责声明 :这是Xonix的解决方案。 If you like it vote him up. 如果您喜欢,请投票给他 But as it took me some head-scratching to figure out what was going on, I thought I might just as well offer my comments so others could benefit. 但是,由于我花了很多力气才想出正在发生的事情,我想我也可以发表自己的评论,以便其他人可以从中受益。

At first, here is his solution as a proper clause: 首先,这是他作为适当子句的解决方案:

criminal(K):-
    member(K,[a,b,c,d]),
    (K\=a -> A=1;A=0),
    (K=d  -> B=1;B=0),
    (K=b  -> C=1;C=0),
    (K\=d -> D=1;D=0),
    A+B+C+D=:=1.

And it goes like this: 它是这样的:

At first, he runs through the list of individuals (have to be lower case, so they're not variables). 首先,他浏览了个人列表(必须为小写,因此它们不是变量)。 K is instantiated to each of them in turn. K依次实例化到他们每个人。

With each possible value of K he runs through the rest of the clause. 对于K每个可能值,他遍历该子句的其余部分。 K can be interpreted as the hypothesis who the criminal is. K可以解释为罪犯是谁的假设。 The next 4 lines are to provide bindings to each of the variables A, B, C and D. You can read them like this: Under the assumption that a is not the criminal, a is truthful otherwise not. 接下来的4行将提供对变量A,B,C和D的绑定。您可以按以下方式阅读它们:在a不是罪犯的假设下,a是真实的,否则就不是。 Under the assumption that d is the criminal, b is truthful otherwise not. d是罪犯的假设下,b是真实的,否则不是。 Asf. Asf。 That is, the variables A, B, ... capture the truthfulness of the corrsponding individual, given a specific criminal. 即,变量A,B,...捕获了给定特定罪犯的相应个人的真实性。

As a known constraint is the fact that only one of them is truthful, the sum of their truth values must be 1. On backtracking, Prolog makes the next binding for K, and runs through it again. 一个已知的约束条件是,只有其中一个是真实的,它们的真实值之和必须为1。回溯时,Prolog对K进行下一个绑定,然后再次遍历。 Turns out the constraint is only satisfied if a is the criminal (and d is telling the truth, if I'm not mistaken). 事实证明,只有在a是罪犯的情况下才满足约束条件(如果我没记错的话, d是在说实话)。 Cute. 可爱。

Here is another solution which I find a bit less cryptic than Xonix's. 这是另一个解决方案,我发现它比Xonix的解决方案少一些神秘性。 Tested in SWI-Prolog. 在SWI-Prolog中测试。

% To find a criminal and the truthteller
% 1. Pick a possible criminal
% 2. Pick a possible truthteller and the remaining liars
% 3. Assert that the truthteller's statement is the truth
% 4. Assert that every liar's statement is not the truth
% If both the assertions succeed
% then we have found a criminal and the truthteller.
criminal_and_truthteller(Criminal, Truthteller) :-
    Group = [a, b, c, d],
    member(Criminal, Group),
    select(Truthteller, Group, Liars),
    statement(Truthteller, Criminal, Truth),
    Truth,
    forall(
        member(Liar, Liars),
        (statement(Liar, Criminal, Lie), \+ Lie)
    ).

% Statements
% Arg 1: Who says
% Arg 2: About whom
% Arg 3: Which statement
% e.g. "a claims that a is not a criminal"
statement(a, C, a \= C).
statement(b, C, d  = C).
statement(c, C, b  = C).
statement(d, C, d \= C).

Usage example: 用法示例:

?- criminal_and_truthteller(Criminal, Truthteller).
Criminal = a,
Truthteller = d ;
false.

I ran across this problem and wanted to give it a shot : 我遇到了这个问题,想试一试:

a(K) :- K \== a.
b(d).
c(b).
d(K) :- K \== d.

solve(TruthTeller) :-
    member(K, [a, b, c, d]),
    xor([a(K), b(K), c(K), d(K)], Truth),
    Truth =.. [TruthTeller|_].

xor([Head|Tail], Result) :-
    (   call(Head)
     -> forall(member(X, Tail), \+ call(X)), Result = Head
     ;  xor(Tail, Result)).

A similar problem and corresponding solution can also be found here: 在这里也可以找到类似的问题和相应的解决方案:

https://github.com/LogtalkDotOrg/logtalk3/blob/master/examples/puzzles/jam_thief.lgt https://github.com/LogtalkDotOrg/logtalk3/blob/master/examples/puzzles/jam_thief.lgt

Like the solution posted by Kaarel, is possible to request a justification/explanation for the solution found. 就像Kaarel发布的解决方案一样,可以为找到的解决方案要求理由/解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM