Prolog实现谢尔宾斯基地毯遇阻,寻求技术解决方案
解决Prolog实现谢尔宾斯基地毯的问题
嘿,作为Prolog新手折腾递归图形生成确实容易卡壳,咱们先从你现有的代码出发,一步步把谢尔宾斯基地毯的逻辑补全跑通。
首先先把你给出的代码片段放出来:
rewrite('X', [['X','X','X'],['X',' ','X'],['X','X','X']]). rewrite(' ', [[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]). rec(1, [], CurrentList, [CurrentList]). rec(_, [], CurrentList, CurrentList). rec(0, L, CurrentList, Result):- append(CurrentList, [L], Result). rec(N, [H|T], CurrentList, Result):- atom(H), N > 0, rewrite(H, L), K is N - 1, rec...
现有代码的问题分析
你的思路方向是对的:用rewrite/2定义每个符号的替换规则,用rec/4做递归展开,但几个子句的逻辑有点冲突,比如:
- 多个
rec的base case(比如rec(1, [], ...)和rec(_, [], ...))会导致匹配混乱 - 递归展开时,没有处理
rewrite返回的二维列表,而是直接把它当成普通元素来处理,这会导致层级不对 - 当处理列表中的元素时,没有考虑递归展开后需要把多行合并的逻辑(谢尔宾斯基地毯是按行来生成的,每一层要把三行分别拼接)
修正后的完整实现
咱们重新梳理逻辑,核心是:
- 定义初始的1阶地毯(就是单个'X')
- 递归时,把当前每一行的每个符号替换成对应的3行,然后把三部分的行分别拼接起来
- 最后把生成的二维列表打印出来,方便看效果
完整代码如下:
% 定义替换规则:X替换成3x3的块,空格替换成全空格块 rewrite('X', [['X','X','X'], ['X',' ','X'], ['X','X','X']]). rewrite(' ', [[' ',' ',' '], [' ',' ',' '], [' ',' ',' ']]). % 递归的base case:0阶时,直接返回原元素组成的单一行 rec(0, Symbol, [Symbol]). % 递归步骤:对Symbol进行替换,然后对替换后的每一行递归展开K阶(K=N-1) rec(N, Symbol, Result) :- N > 0, K is N - 1, rewrite(Symbol, Block), % 对Block中的每一行递归展开,得到展开后的行列表 maplist(rec_row(K), Block, ExpandedRows), % 把三部分的行分别拼接:第一行+第二行+第三行 append(ExpandedRows, Result). % 处理一行的递归展开:把行里的每个元素递归展开K阶,然后把对应位置的行拼接 rec_row(K, Row, ExpandedRow) :- % 对行里的每个符号递归展开K阶,得到每个符号对应的行列表 maplist(rec(K), Row, SymbolRows), % 把每个符号的第1行、第2行、第3行分别拼接起来 transpose(SymbolRows, Transposed), maplist(append, Transposed, ExpandedRow). % 辅助谓词:转置二维列表(用来把每个符号的行对齐拼接) transpose([], []). transpose([[]|_], []). transpose(Matrix, [Row|Rows]) :- maplist(head, Matrix, Row), maplist(tail, Matrix, RestMatrix), transpose(RestMatrix, Rows). head([H|_], H). tail([_|T], T). % 生成并打印N阶谢尔宾斯基地毯 sierpinski(N) :- rec(N, 'X', Carpet), maplist(print_row, Carpet). print_row(Row) :- atom_chars(Atom, Row), writeln(Atom).
代码解释
rewrite/2:保持你原来的定义,每个符号对应3x3的块rec/3:递归生成N阶地毯,base case是0阶直接返回单元素行;N>0时先替换成3x3块,再对每一行递归展开rec_row/3:处理单行的展开,把行内每个符号的展开结果转置后拼接,这样就能把三个符号的第一行拼在一起,第二行拼在一起,以此类推transpose/2:辅助谓词,用来转置二维列表,实现行对齐拼接sierpinski/1:入口谓词,调用递归生成后打印每一行
测试效果
比如调用sierpinski(2).,会输出:
XXXXXXXXXXX X XX XX XX XXXXXXXXXXX XXX XXX X X X X XXX XXX XXXXXXXXXXX X XX XX XX XXXXXXXXXXX
这样就能正确生成谢尔宾斯基地毯啦~
内容的提问来源于stack exchange,提问作者Mesieur Kobayashi
相关产品推荐
相关产品推荐

