【问题标题】:Force Prolog to choose unique values of variables强制 Prolog 选择变量的唯一值
【发布时间】:2013-01-29 19:33:30
【问题描述】:

好的,我是 Prolog 的新手,如果这是微不足道的事情,请原谅,但我似乎找不到合适的优雅答案。我正在尝试在learnprolognow.org 上进行练习,练习 2.4(填字游戏)。

该练习提供了以下事实:

   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(V1, V2, V3, H1, H2, H3) :-
   word(V1, V1a, V1bH1b, V1c, V1dH2b, V1e, V1fH3b, V1g), 
   word(V2, V2a, V2bH1d, V2c, V2dH2d, V2e, V2fH3d, V2g), 
   word(V3, V3a, V3bH1f, V3c, V3dH2f, V3e, V3fH3f, V3g), 
   word(H1, H1a, V1bH1b, H1c, V2bH1d, H1e, V3bH1f, H1g), 
   word(H2, H2a, V1dH2b, H2c, V2dH2d, H2e, V3dH2f, H2g), 
   word(H3, H3a, V1fH3b, H3c, V2fH3d, H3e, V3fH3f, H3g).

V1aV1g 等是每个单词的字符,V1bH1bV3fH3f 是填字游戏中单词之间的共同字符。

该解决方案似乎有效,但结果是产生重复值,第一个结果是:

?- crossword(V1, V2, V3, H1, H2, H3).
V1 = astante,
V2 = baratto,
V3 = statale,
H1 = astante,
H2 = baratto,
H3 = statale .

如何强制 Prolog 拥有 V1 \= V2 \= V3 \= H1 \= H2 \= H3 ? 如果我一个一个地做,我需要 120 个排列,所以必须有一个更快的方法,而且这是一个初学者练习,所以我一定会遗漏一些东西。

我找到了this similar question,但是提供的答案似乎很复杂,希望有更简单的方法。我在 Ubuntu 上使用 swi-prolog,以防万一。

谢谢。

【问题讨论】:

  • dif(V1,V2)maplist(dif(V1),[V2,V3,V3])
  • 但是div(V1, V2) 不等于V1 \= V2,所以我还是要做120次才能保证6个变量不一样?!
  • 请注意,它是 dif/2。是的,它是一样的。使用 maplist,您已经缩短了。为了进一步缩短,定义一个辅助谓词 alldif/1,如果列表的所有元素都不同,则该谓词为真。
  • 好的,我该怎么做?请记住,我还是一个刚开始的初学者,所以不要以为我可以填写etc.insert more here
  • 如果你在游戏的早期阶段就不要试图向前跳;逐步解决问题。首先,无论如何,您都必须输入更详细的解决方案。然后,当你接触到更高级的东西时,你会更加欣赏它。

标签: prolog crossword prolog-dif


【解决方案1】:

使用alldif/1 定义如下:

alldif([]).
alldif([E|Es]) :-
   maplist(dif(E), Es),
   alldif(Es).

这甚至可以用于最一般的查询:

?- alldif(Es).
Es = [] ;
Es = [_G1924] ;
Es = [_G2061, _G2064],
dif(_G2061, _G2064) ;
Es = [_G2163, _G2166, _G2169],
dif(_G2163, _G2169),
dif(_G2163, _G2166),
dif(_G2166, _G2169) ;
Es = [_G2309, _G2312, _G2315, _G2318],
dif(_G2309, _G2318),
dif(_G2309, _G2315),
dif(_G2309, _G2312),
dif(_G2315, _G2318),
dif(_G2312, _G2315),
dif(_G2312, _G2318) ...

目标maplist(dif(E),Es)的含义最好通过查看答案来理解:

?- maplist(dif(E),Es).
Es = [] ;
Es = [_G1987],
dif(E, _G1987) ;
Es = [_G2040, _G2043],
dif(E, _G2043),
dif(E, _G2040) ;
Es = [_G2093, _G2096, _G2099],
dif(E, _G2099),
dif(E, _G2096),
dif(E, _G2093) ;
Es = [_G2146, _G2149, _G2152, _G2155],
dif(E, _G2155),
dif(E, _G2152),
dif(E, _G2149),
dif(E, _G2146) ...

也就是说,Es 是与E 完全不同的元素列表。目标maplist(dif(E),[A,B,C]) 将第一个元素(在本例中为dif(E))与列表的每个元素相结合。因此dif(E,A), dif(E,B), dif(E,C)

【讨论】:

  • 干杯!我刚刚添加了您指出的alldif,并在我的crossword() 子句末尾添加了alldif([V1, V2, V3, H1, H2, H3])。谢谢你的帮助。必须有一个简单的方法。
  • @jbx:你也可以在开头加上!这样一来,搜索空间就会减少
  • 好主意,谢谢。它已经足够好,我设法让练习发挥作用:)
  • 最后一个小问题,可能对潜在读者有用。 maplist(dif(E), Es) 实际上在做什么? dif/1E 相比是什么? maplist/2 究竟会提供什么?
  • @jbx:问 Prolog:?- maplist(dif(E), Es). 的答案非常清楚!
【解决方案2】:

length(List, N):N是列表的长度
sort(List, SortedList):SortedList是List的排序版本(重复元素被删除)

另一方面,拥有可用单词列表并在使用时删除它可能会更快;不仅您不必在最后进行检查,而且您将避免无意义的实例化(A1 = foo, A2 = foo 将立即停止,而不是在最后被拒绝)。换句话说,分支修剪。

【讨论】:

  • 谢谢,但是你能详细说明一下我如何使用练习提供的事实来最终实现crossword(V1, V2, V3, H1, H2, H3),这保证每个都是不同的?这就是本练习的重点。
【解决方案3】:

@false 在 cmets 中告诉你什么;或者我喜欢用domain selection:

selectM([A|As],S,Z):- select(A,S,S1),selectM(As,S1,Z).
selectM([],Z,Z).

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(Words) :- findall(W, word(_,W), WS),
   Words = [[ _,A,_,B,_,C,_], 
            [ _,D,_,E,_,F,_], 
            [ _,G,_,H,_,I,_],
            [ _,A,_,D,_,G,_],
            [ _,B,_,E,_,H,_],
            [ _,C,_,F,_,I,_]],
   selectM( Words, WS, _).

【讨论】:

  • 谢谢,你的方法看起来很优雅。但是你修改了练习中给出的事实清单?
  • @jbx 是的,我做到了。 :) 如果不允许,那么您可以将一个转换为另一个:wordL(W):- word(_, A,B,C,D,E,F,G), W=[ 在此处插入更多 ].。然后您可以在对findall 的调用中使用wordL 而不是word
  • 好吧,这不是我不被允许的,这就是练习的方式,我正在尝试慢慢学习。 insert more here 会有什么?
  • @jbx 我把它留给你弄清楚。 :) 说,对于word(day, d, a, y),我们想要W=[d,a,y],对吧?如果现在这对你来说很难,可能最好先学习一些 Prolog 的介绍。
  • 是的,这就是重点。该练习是 learnprolognow.org 的第 2 章(第 1 章仅解释原子、简单术语等)。我在问题中明确表示我是初学者,所以我目前很难弥合差距。不过也谢谢你的回答。
猜你喜欢
  • 2021-04-19
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多