创建互斥或prolog

时间:2017-10-30 18:15:46

标签: prolog

假设你有一群下棋的人。你想确定一个玩家是否存在从不输给任何人(不败)。假设事实是以赢得的(詹姆斯,汤姆)给出的。赢了(詹姆斯,彼得),赢了(克雷格,汤姆)。失去了(皮特,汤姆)。然后玩家X根据条件从未输过。

undefeated(X) :- \+ won(_, X), \+ lost(X, _).

如此不败(詹姆斯)是真实的,不败(克雷格)是真实的但不败(汤姆)和不败(彼得)是假的。现在问题在调用不败(X)时出现,因为这将只返回否。要解决这个问题,我们需要一个在开始时始终为true的语句,因此我们为分别播放白色和黑色片段的播放器添加事实whiteplayer()和blackplayer()。

whiteplayer(james).
whiteplayer(craig).
whiteplayer(tom).
whiteplayer(peter).
blackplayer(james).
blackplayer(peter).
blackplayer(tom).

并将不败变为:

undefeated(X) :- (whiteplayer(X); blackplayer(X)), \+ won(_, X), \+ lost(X, _).

但现在我们遇到了一个新问题。查询不败(X)给出了解决方案詹姆斯,克雷格,詹姆斯,这发生了,因为詹姆斯同时扮演白色和黑色棋子,但克雷格只扮演白色棋子。所以问题是不败(詹姆斯)继续为白人(詹姆斯)和黑人(詹姆斯)继续,我怎么能做到这样只有在回溯时才进行其中一个?

2 个答案:

答案 0 :(得分:3)

如果您的事实和规则允许变量的特定实例化以多种方式成功,那么除非您使用剪切(这通常也会消除有效的解决方案,这是不可取的),否则您将获得重复,或者您可以收集使用setof(或“手动”)的冗余子解决方案可以消除重复。

所以你可以这样做:

validplayer(X) :- whiteplayer(X) ; blackplayer(X).

undefeated(Player) :-
    setof(P, validplayer(P), Players),
    member(Player, Players),
    \+ won(_, Player), \+ lost(Player, _).

理想情况下,如果您可以定义validplayer/1以使其对任何给定的玩家成功一次并且不切割,则会更好。但是你目前对事实的定义并没有实现这一点。

我还建议您不要同时使用won/2lost/2个事实,因为won(X, Y)相当于lost(Y, X)。最好坚持使用其中一个。希望您的数据库不同时包含won(john, paul)lost(paul, john),否则上述解决方案仍会产生重复项,您需要setof/3上的undefeated/1:{{ 1}}。

答案 1 :(得分:0)

如果你知道至少有一个人从X获胜,那么X并不是不败的。你只需尝试找到至少一个ZZX获胜。如果发生这种情况,则意味着prolog找到一个匹配,它会尝试返回true而你只是反转这个值是假的并且削减了所有其他分支。

对于没有不败的人也是如此。在这种情况下,prolog找不到匹配并返回false而不反转它的值。

这是你的代码,如果我理解你的问题,那么使用guitracer看看发生了什么总是好的。

won(james,tom). 
won(james,peter).
won(craig,tom). 
lost(peter,tom).



undefeated(X):-
  \+ won(_Z,X),!.