填字游戏

转载自:https://mp.weixin.qq.com/s/PbopBAcQo9q37_sUanh4zw

给定一个填字游戏和一组单词的空的(或几乎空的)框架。问题是将这些词放入框架中。

特定的填字游戏在文本文件中指定,该文件首先以任意顺序列出单词(每行一个单词)。然后,在空行之后,定义填字游戏框架。在此框架规范中,空字符位置由点(.)表示。为了简化解决方案,字符位置还可以包含预定义的字符值。然而谜题在文件p7_09a.dat中定义,其它谜题示例为p7_09b.dat和p7_09d.dat。还有一个没有解的谜题示例(p7_09c.dat)。

 

单词是至少两个字符的字符串(字符列表)。纵和横字谜框架中字符位置的水平或垂直顺序称为网格。我们的问题是找到一种在网格上放置相容单词的方法。

 

提示:

1)问题不容易。您将需要一些时间来彻底了解它。因此,不要太早放弃!请记住,目标是一个清晰的解,而不仅仅是快速而肮脏的骇客!

(2)读取数据文件是一个棘手的问题,文件p7_09-readfile.pl中提供了解决方法。使用谓词read_lines/2。

(3)出于效率的考虑,至少对于较大的谜题,以特定顺序对单词和位置进行排序非常重要。对于这一部分问题,“Prolog 列表练习 3” 的解决方案可能会非常有帮助。

 

程序文件是:p7_09.pl

 

:- ensure_loaded('p7_09-readfile.pl').  % 用于读取数据文件

 

crossword :-

write('usage: crossword(File)'), nl,

write('or     crossword(File,Opt)         with Opt one of 0,1, or 2'), nl,

write('or     crossword(File,Opt,debug)   for extra output'), nl.

 

:- crossword.

 

% crossword/1 无需优化即可运行(建议不要用于大文件)

crossword(FileName) :- 

crossword(FileName,0).

 

% crossword/2 以给定的优化运行,没有调试输出

crossword(FileName,Opt) :- 

crossword(FileName,Opt,nodebug).

 

% crossword/3 以给定的优化和给定的调试方式运行

crossword(FileName,Opt,Debug) :-

read_lines(FileName,Lines),  % 从文件p99-readfile.pl的谓词 read_lines/2 返回一个字符列表

separate(Lines,Words,FrameLines),

length(Words,NWords), 

construct_squares(FrameLines,Squares,MaxRow,MaxCol),

debug_write(Debug,Squares),

construct_sites(Squares,MaxRow,MaxCol,Sites),

length(Sites,NSites),

check_lengths(NWords,NSites), 

solve(Words,Sites,Opt,Debug), % 做实际的工作

show_result(Squares,MaxRow,MaxCol).

 

debug_write(debug,X) :- 

!, 

write(X), nlnl.

debug_write(_,_).

 

check_lengths(N,N) :- !.

check_lengths(NW,NS) :- 

NW \= NS

write('Number of words does not correspond to number of sites.'), nl,

fail.

 

% 输入准备

% 解析数据文件并将单词列表与框架描述分离

separate(Lines,Words,FrameLines) :-

trim_lines(Lines,LinesT),

parse_non_empty_lines(LinesT-L1,Words),  % 差异列表!

parse_empty_lines(L1-L2),

parse_non_empty_lines(L2-L3,FrameLines),

parse_empty_lines(L3-[]).

 

% 删除行尾的空白

trim_lines([],[]).

trim_lines([L|Ls],[LT|LTs]) :- 

trim_line(L,LT), 

trim_lines(Ls,LTs).

 

trim_line(L,LT) :- 

reverse(L,RL), 

rm_white_space(RL,RLT), 

reverse(RLT,LT).

 

rm_white_space([X|Xs],L) :- 

char_type(X,white), 

!, 

rm_white_space(Xs,L).

rm_white_space(L,L).      

 

% 将单词行与框架行分开

parse_non_empty_lines([L|L1]-L2,[L|Ls]) :- 

L \= [], 

!, 

parse_non_empty_lines(L1-L2,Ls).

parse_non_empty_lines(L-L,[]).

 

parse_empty_lines([[]|L1]-L2) :- 

!, 

parse_empty_lines(L1-L2).

parse_empty_lines(L-L).

 

% 一个方框是单个字符的位置。作为Prolog项,方框的形式为sq(Row,Col,X),其中X表示字符,Row和Col定义拼图框内的位置。方框只是所有sq/3项的列表。

 

construct_squares(FrameLines,Squares,MaxRow,MaxCol) :- %(+,-,+,+)

construct_squares(FrameLines,SquaresList,1),

flatten(SquaresL

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经典游戏:在3*3个方格的方阵中要入数1到N(N>=10)内的某9个数,每个方格一个整数,使得所有相邻两个方格内的两个整数之和为质数。试求出所有满足这个要求的各种数法。 //我们可以通过改变N的值来求不同数范围的质数数组,如果超出整型的范围,还需要改变数据类型。 //f[i]来记录数i是否使用过, //T[i]用来记录下一个可以插在数i后面的与其和为质数的数在F[i][]中的位置。 //用F[i][j]来存储按数从小到大的顺序得出的与数i和为质数的第j个数, //例如:F[1][2]存储的是与数1的和为质数的第二个数,我们可以通过查询数组F[][]的第一行找出第二个不为0 //值,然后将当前数组单元的列号存储到F[1][2]中,即F[1][2] = 4。 //算法思想是通过查询二维数组F[][],来确定下一个可以插入数组num[]的未使用过的数,并记录该数位于数组F[][]的位置, //以便回溯时寻找下一个符合要求的数。如果不存在这样的未使用的数,则需要回溯到上一个已插入num[]的数, //寻找下一个可以插在该数后面的未使用过的数进行插入,如果所有的数都已经插入到num[]中, //如是则打印结果。当所有数都已插入num[]中,开始 //进行回溯,重复上述操作,寻找其他符合要求的序列。 //这里面有一个关键在于处理位于num数组右下角四个格子的数时,不光需要判断与前一个数i的关系,还需要判断其头顶上的元素之和是否为素数。 //程序中有一大段代码是处理i和j的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值