PROLOG中的填字游戏解算器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PROLOG中的填字游戏解算器相关的知识,希望对你有一定的参考价值。
天堂岛的克里奥尔语有14个字:“放弃”,“鲍鱼”,“anagram”,“船”,“船夫”,“孩子”,“连接”,“优雅”,“增强”,“岛屿”,男人“,”沙子“,”太阳“和”女人“。
天堂时报发布了这个填字游戏:
填字游戏包含14个单词中的一些但没有其他单词。
写一个从...开始的Prolog程序
word(X) :-
member(X,
[
[a,b,a,n,d,o,n], [a,b,a,l,o,n,e], [a,n,a,g,r,a,m],
[b,o,a,t], [b,o,a,t,m,a,n], [c,h,i,l,d],
[c,o,n,n,e,c,t], [e,l,e,g,a,n,t], [e,n,h,a,n,c,e],
[i,s,l,a,n,d], [m, a, n], [s,a,n,d],
[s,u,n], [w, o, m, a, n]
]).
solution(H1,H2,H3,V1,V2,V3) :-
并以这样的方式定义谓词solution
solution(H1,H2,H3,V1,V2,V3)
当且仅当H1
,H2
,H3
,V1
,V2
和V3
是天堂岛的有效单词时才会成立,这些单词在写入上面给出的网格时形成有效的填字游戏。 (例如,H1
的第二个字母应与V1
的第二个字母重合。)
使用查询
?- solution(H1,H2,H3,V1,V2,V3).
解决填字游戏。找到填字游戏的所有解决方案。
提示:您可能希望从较小的填字游戏和不太丰富的词汇开始。
只要看一下图片,用字母写的是单词,你就可以在图片中找到所有内容,在Prolog行中进行转换(我的解决方案有12行,一行有2行)。
[编辑]每个人都有自己的解决方案,这是我的:
solution(H1,H2,H3,V1,V2,V3) :-
H1 = [_,A2,_,A4,_,A6,_],
H2 = [_,B2,_,B4,_,B6,_],
H3 = [_,C2,_,C4,_,C6,_],
V1 = [_,A2,_,B2,_,C2,_],
V2 = [_,A4,_,B4,_,C4,_],
V3 = [_,A6,_,B6,_,C6,_],
maplist(word, [H1,H2,H3,V1,V2,V3]).
PS我最初写的是单词(H1),单词(H2)......
独特的领域选择select/2
做的伎俩:
select([A|As],S):- select(A,S,S1),select(As,S1).
select([],_).
words(X) :- X = [
[a,b,a,n,d,o,n], [a,b,a,l,o,n,e], [a,n,a,g,r,a,m],
[b,o,a,t], [b,o,a,t,m,a,n], [c,h,i,l,d],
[c,o,n,n,e,c,t], [e,l,e,g,a,n,t], [e,n,h,a,n,c,e],
[i,s,l,a,n,d], [m, a, n], [s,a,n,d],
[s,u,n], [w, o, m, a, n]
].
solve(Crossword):- words(Words),
Crossword = [ [_,A2,_,A4,_,A6,_],
[_,B2,_,B4,_,B6,_],
[_,C2,_,C4,_,C6,_],
[_,A2,_,B2,_,C2,_],
[_,A4,_,B4,_,C4,_],
[_,A6,_,B6,_,C6,_] ],
select(Crossword, Words).
solve:- solve(Crossword),
maplist(writeln, Crossword), writeln(';'), fail
; writeln('No more solutions!').
测试:
7 ?- solve.
[a, b, a, n, d, o, n]
[e, l, e, g, a, n, t]
[e, n, h, a, n, c, e]
[a, b, a, l, o, n, e]
[a, n, a, g, r, a, m]
[c, o, n, n, e, c, t]
;
[a, b, a, l, o, n, e]
[a, n, a, g, r, a, m]
[c, o, n, n, e, c, t]
[a, b, a, n, d, o, n]
[e, l, e, g, a, n, t]
[e, n, h, a, n, c, e]
;
No more solutions!
此解决方案仅允许在拼图中使用唯一的单词(不允许重复)。这可能是也可能不是你想要的。
不是Prolog程序本身,但使用Constraint Logic Programming的解决方案可以在Hakan Kjellerstrand's excellent blog on CP中找到。它在ECLiPSe中,但很容易适应其他具有有限域求解器的Prolog系统。使用CLP而不是纯Prolog将使搜索更快。
solution(H1, H2, H3, V1, V2, V3) :-
crosswordize([H1,H2,H3], [V1,V2,V3]),
maplist(word, [H1,H2,H3,V1,V2,V3]).
crosswordize([], [[_],[_],[_]]).
crosswordize([[_, X1, _, X2, _, X3, _]|Lines],
[[_, X1|R1], [_, X2|R2], [_, X3|R3]]) :-
crosswordize(Lines, [R1,R2,R3]).
算法并不难:
- 我们通过
crosswordize/2
谓词调用构建网格 - 我们告诉prolog每个列表都是一个单词
crosswordize/2
谓词在构建线条时一次通过两个单元格的列。如果你没有得到它,你仍然可以像Will那样“硬编码”它,它也有效!
这里的理论是检查垂直和水平单词中与自身对应的字母。这可以通过在word
规则中使用占位符来实现。检查这个要点https://gist.github.com/ITPol/f8f5418d4f95015b3586它给出了一个答案,声称没有重复。但是,来自SQL,我认为正确地限制重复将需要一个V1 @< V2
的解决方案;因为仅仅使用“不等于”是不够的。请原谅多个“[k] nots”;它实际上并不那么复杂。双关语(:
以上是关于PROLOG中的填字游戏解算器的主要内容,如果未能解决你的问题,请参考以下文章