我决定写一个填字游戏生成器:crossword(Rows, Columns, WordList, CrosswordGrid)
。
预期用途:
?- crossword(6, 6, [apple, pear, grape, rum], C).
C = [
[a, _, g, _, _, r],
[p, _, r, _, _, u],
[p, e, a, r, _, m],
[l, _, p, _, _, _],
[e, _, e, _, _, _],
[_, _, _, _, _, _]
]
下面是旨在实现正确填字游戏的Prolog程序。通过一次在填字游戏网格中填充一个水平或垂直单词来工作。
% Prolog implementation: SWI-Prolog.
:- use_module(library(clpfd)). % Imports transpose/2 for transposing a matrix.
% Generates a matrix (Grid) with the specified number of rows and columns.
matrix(Rows, Cols, Grid) :-
length(Grid, Rows),
maplist(length_list(Cols), Grid).
% Like length/2, but with parameters in reverse order.
length_list(Length, List) :- length(List, Length).
% Xs is a sublist of AsXsBs.
% e.g. sublist([3,4], [1,2,3,4,5]).
sublist(Xs, AsXsBs) :-
append(AsXs, _, AsXsBs),
append(_, Xs, AsXs).
% Place a word HORIZONTALLY in the grid.
place(Word, Grid) :-
atom_chars(Word, Chars),
member(Row, Grid),
sublist(Chars, Row).
% Place a word VERTICALLY in the grid.
place(Word, Grid) :-
atom_chars(Word, Chars),
transpose(Grid, TGrid),
member(TRow, TGrid),
sublist(Chars, TRow).
crossword(Rows, Cols, [W|Ws], Grid) :-
matrix(Rows, Cols, Grid),
place(W, Grid), % Place the first word.
crossword(Rows, Cols, Ws, Grid). % Place the other words.
crossword(_,_,[],_).
上面的程序在生成包含指定单词的网格时效果很好。但是,某些解决方案不是有效的填字游戏:
C = [
[p, e, a, r, _, _],
[r, u, m, _, _, _],
[a, p, p, l, e, _],
[g, r, a, p, e, _],
[_, _, _, _, _, _],
[_, _, _, _, _, _]
];
C = [
[p, e, a, r, u, m],
[a, p, p, l, e, _],
[g, r, a, p, e, _],
[_, _, _, _, _, _],
[_, _, _, _, _, _],
[_, _, _, _, _, _]
]
我现在意识到了这一点:在网格中生成一行时,程序必须考虑上下一行中的字母,因此该行中的单词不会与相邻行中的单词“冲突”。 >
但是,由于我是Prolog的初学者,因此我不知道如何解决该问题,仅将其用于解决简单的教科书练习。该程序标志着我理解Prolog的巨大飞跃。
所以问题是:
我需要在程序中进行哪些更改以消除错误的解决方案?提示是最欢迎的。
有没有更好的方法来表示填字游戏网格?