SWI Prolog上的琐事冠军逻辑谜题

时间:2013-04-04 10:53:39

标签: prolog

我是使用swi Prolog的新手,现在我正在尝试使用Prolog来解决这个逻辑难题http://www.allstarpuzzles.com/logic/00335.html

但是当我试图运行该程序时,该程序似乎停止响应并且Prolog冻结了。看来我在确定每支球队的得分时遇到了问题。 这是我的Prolog代码:

team(dirtydozen).
team(plough).
team(barflyers).
team(threestooges).
team(friends).

pub(maid).
pub(old).
pub(clown).
pub(king).
pub(queen).

score(75).
score(74).
score(73).
score(72).
score(71).
score(70).
score(69).
score(68).
score(67).
score(66).
score(65).
score(64).
score(63).
score(62).
score(61).
score(60).


solve :-
  score(Score1),score(Score2),score(Score3),score(Score4),score(Score5),
  pub(Pub1),pub(Pub2),pub(Pub3),pub(Pub4),pub(Pub5),

  Hasil = [[dirtydozen,Pub1,Score1],
       [plough,Pub2,Score2],
       [barflyers,Pub3,Score3],
       [threestooges,Pub4,Score4],
       [friends,Pub5,Score5]],
 Score1 is Score2 + 6,
 Score1 is Score3 + 9,
 \+ member([threestooges,maid,_],Hasil),

 member([friends,_,A],Hasil),
 member([_,old,B],Hasil),
 member([_,clown,C],Hasil),
 member([_,king,D],Hasil),
 (A-B) is 2*(C-D),
 member([_,queen,E],Hasil),
 member([threestooges,_,F],Hasil),
 F >= E+3.

1 个答案:

答案 0 :(得分:1)

几乎是正确的。只有四个问题。 ;-) 首先,这是一个几乎可以工作的版本:

team(dirtydozen).
team(plough).
team(barflyers).
team(threestooges).
team(friends).

pub(maid).
pub(old).
pub(clown).
pub(king).
pub(queen).

score(75).
score(74).
score(73).
score(72).
score(71).
score(70).
score(69).
score(68).
score(67).
score(66).
score(65).
score(64).
score(63).
score(62).
score(61).
score(60).

solve(Hasil) :-
    Hasil = [[dirtydozen,Pub1,Score1],
         [plough,Pub2,Score2],
         [barflyers,Pub3,Score3],
         [threestooges,Pub4,Score4],
         [friends,Pub5,Score5]],
    member([friends,_,A],Hasil),
    member([_,old,B],Hasil),
    member([_,clown,C],Hasil),
    member([_,king,D],Hasil),
    member([_,queen,E],Hasil),
    member([threestooges,_,F],Hasil),
    \+ member([threestooges,maid,_],Hasil),
    score(Score2),
    Score1 is Score2 + 6,
    score(Score3),
    Score1 is Score3 + 9,
    score(Score1),
    score(Score4),
    score(Score5),
    AB is A-B,
    AB is 2*(C-D),
    F >= E+3,
    pub(Pub1),
    pub(Pub2),
    pub(Pub3),
    pub(Pub4),
    pub(Pub5).

几乎,因为它提供了解决方案,并且速度快,并且根据您的规范它们是正确的。但是,有很多因为你没有指定所有的酒吧/团队/分数必须彼此不同,所以例如

[[dirtydozen,old,75],[plough,clown,69],[barflyers,queen,66],
 [threestooges,king,75], [friends,old,63]]

是一个解决方案,即使“旧”和“75”在其中两次。如果您使用的是SWI,请从clp_fd包中添加all_different个调用或手动执行:

A \= B, A \= C, ... B \= C etc.

现在,关于冻结:这只是因为你的条款的次优顺序。首先查看scorepub。在solve谓词的前两行中,这两个谓词的每个可能的排列都分配给Score[N]Pub[N]变量。尝试计算有多少可能的任务!只有这样,您的程序才会检查相关作业是否符合规则。

通过重新排序您的条件,我从一开始就排除了大量的作业。以这些行为例:

score(Score1), score(Score2), Score1 is Score2 + 2,...

这可以这样评价:

Score1 = 75, Score2 = 75, 75 is 75+2? 
Score1 = 74, Score2 = 75, 74 is 75+2? 
Score1 = 73, Score2 = 75, 73 is 75+2? 
Score1 = 72, Score2 = 75, 72 is 75+2? 
...

总而言之,必须检查最多225个Score1和Score2的组合,以确定它们是否是正确的分配。

现在让我们考虑重新排序的版本:

score(Score2), Score1 is Score2 + 2, score(Score1),...

评估现在沿着这些方向运行:

Score2 = 75, Score1 = 77, score(77)?
Score2 = 74, Score1 = 76, score(76)?
Score2 = 73, Score1 = 75, score(75)?

我们只有15个有效作业。所以规则是:尝试将这些变量彼此修复,以免让树展开超出必要的范围。修复移动目标!

唯一的另外两个小问题:1)(A-B) is 2*(C-D)不起作用,因为它指出,评估2*(C-D)的结果必须不是整数,而是形式{ {1}}。引入一个中间变量来解决。 2)你没有让(A-B)返回任何有用的东西,所以只说solve。不知道那是不是你想要的。 ; - )