填字游戏

这是一个用Prolog编写的填字游戏解决方案。程序读取包含单词列表和填字游戏框架的文本文件,然后找到将单词放入框架的方法。程序提供不同级别的优化选项,并能处理不同大小的谜题。通过调整优化参数,可以显著减少解决大谜题所需的时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: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(SquaresList,Squares),

maxima(Squares,0,0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值