带序言的填字游戏

crossword puzzle with prolog

目前我正在做序言tutorial

有一个用 5 个单词解决填字游戏的练习。

我的问题是 Prolog 很早就停止了对我的解决方案的统一。

看起来是这样的:

并且给出了一个小的知识库:

   word(astante,  a,s,t,a,n,t,e). 
   word(astoria,  a,s,t,o,r,i,a). 
   word(baratto,  b,a,r,a,t,t,o). 
   word(cobalto,  c,o,b,a,l,t,o). 
   word(pistola,  p,i,s,t,o,l,a). 
   word(statale,  s,t,a,t,a,l,e).

为了解决这个任务,我有一个谓词 crossword/6

所以我认为谓词 crossword 必须包含 6 个由变量组成的词,并且在两个词交叉的每个字段中我都设置了相同的变量。

crossword(word(H1, A1, B1, C1, D1, E1, F1, G1),
          word(H2, A2, B2, C2, D2, E2, F2, G2),
          word(H3, A3, B3, C3, D3, E3, F3, G3),
          word(V1, _1, B1, _2, B2, _3, B3, _4),
          word(V2, _5, D1, _6, D2, _7, D3, _8),
          word(V3, _9, F1, _10, F2, _11, F3 _12)).

在 SWI-Prolog 中,我输入了以下请求:

?- crossword(H1, H2, H3, V1, V2, V3).

所以我问了一个填字游戏的答案。

我得到的结果是这样的:

H1 = word(_720, _722, _724, _726, _728, _730, _732, _734),
H2 = word(_738, _740, _742, _744, _746, _748, _750, _752),
H3 = word(_756, _758, _760, _762, _764, _766, _768, _770),
V1 = word(_774, _776, _724, _780, _742, _784, _760, _788),
V2 = word(_792, _794, _728, _798, _746, _802, _764, _806),
V3 = word(_810, _812, _732, _816, _750, _820, _768).

问题:为什么Prolog这么早就停止统一了?为什么 return 没有任何解决方案?

你的代码声明了一个简单的事实:有一个crossword/6谓词,它的参数是word/8个谓词,并且word/8个谓词的一些参数是相同的。特别是,由于 crossword/6 被声明为简单事实,因此 crossword/6 声明中的 word/8 谓词与知识库之间没有任何关系(就像 "astoria" 的事实一样不限制 "astante").

的事实

相反,只有文字本身才是简单的事实:

word(astante,  a,s,t,a,n,t,e).
word(astoria,  a,s,t,o,r,i,a).
word(baratto,  b,a,r,a,t,t,o).
word(cobalto,  c,o,b,a,l,t,o).
word(pistola,  p,i,s,t,o,l,a).
word(statale,  s,t,a,t,a,l,e).

因为这些都是没有条件的简单事实,我们总能证明有一个word/8谓词,其第一个参数是astante/0,第二个参数是a/0,第三个参数是s/0,依此类推。

你想说的是,如果这六个词的其他条件成立,那么这六个词就形成了一个有效的解决方案:

crossword( H1, H2, H3, V1, V2, V3 ) :-
  <conditions for a successful crossword solution>.

接下来,定义 crossword/6 的条件,这样一个有效的解决方案是变量与 word/8 谓词的第一个参数统一,如果这些参数的第三个、第五个和第七个参数word/8 争论以正确的方式相互统一。

对于一个(不完整的)例子,如果 H1 的第二个字母是 V1 的第二个字母,H1 的第六个字母是 V3 的第二个字母,我可以说我有一个有效的填字游戏解决方案:

crossword( H1, H2, H3, V1, V2, V3 ) :-
  word( H1, _, TL, _, _, _, TR, _ ),
  word( V1, _, TL, _, _, _, _, _ ),
  word( V3, _, TR, _, _, _, _, _ ).

这里我使用下划线 _ 来避免给名称无关紧要的变量命名。我还使用 TLTR 来表示 "top left" 和 "top right" 以使我自己的推理更容易。 Prolog 认为如果我们可以证明存在 word/8 个谓词,其参数以特定方式统一,则我们可以证明 crossword/6,并搜索这样做的 word/8 个谓词的组合。 "knowledge base" 为每个可能的证明提供了公理。

你现在知道如何完成 crossword/6 定义了吗?请注意,您需要为一些下划线变量(称为 "anonymous variables")命名以完成解决方案,并在 turnstyle 的右侧引入额外的 word/8 项。