【问题标题】:Solving the Numberlink puzzle with prolog用 prolog 解决 Numberlink 难题
【发布时间】:2016-01-27 17:03:03
【问题描述】:

我的作业似乎超出了我的课堂范围(我这么说是因为他们几乎没有教我们任何关于 prolog 的知识),我必须编写一个 prolog 程序来解决 android 上的“Flow Free”游戏。在作业中,它被称为 Numberlink。我可以在一小时内用 C++ 解决这个问题,但是因为我对 prolog 不太熟悉,所以给我带来了麻烦。这是我想做的:

  1. 制作一个包含布尔值的列表,以指示它是否已被访问或使用。
  2. 递归搜索从给定起点到的所有可能路径 使用广度优先搜索找到最短的终点 路径。
  3. 我猜从那里去。

我的尝试包括在网上搜索如何制作列表。当然 prolog 在任何地方都没有很好地记录,所以我空白并放弃了。一位朋友告诉我使用 maplist,我不明白如何使用它来制作包含我需要的列表。

提前致谢。

编辑: 感谢您的链接,但我希望制作一个 2D 列表来代表正在播放的棋盘。函数如下所示:

makeList(size, list):-

其中 size 是一个整数,表示正方形列表 ex 中一维的大小。 (7x7)。

【问题讨论】:

  • Help With Prolog Lists的可能重复
  • 当然,prolog 在任何地方都没有很好地记录,真的吗?
  • 看起来您似乎没有走上正轨。 Prolog 是一种声明性语言。你应该考虑定义每个块之间的关系,然后点击解决按钮。

标签: prolog


【解决方案1】:

这是@CapelliC 解决方案的一个实现。代码是不言自明的。如果两个块相邻并且具有相同的颜色,或者与另一个相同颜色的连接块相邻,则它们是连接的。 (我用 X 和 Y 代替了行和列,这让最后写的条件有点混乱。)

在 SWI-Prolog 中求解

https://flowfreesolutions.com/solution/?game=flow&pack=green&set=5&level=1

connected(P1, P2, M, Visited) :-
    adjacent(P1, P2),
    maplist(dif(P2), Visited),
    color(P1, C, M),
    color(P2, C, M).
connected(P1, P2, M, Visited) :-
    adjacent(P1, P3),
    maplist(dif(P3), Visited),
    color(P1, C, M),
    color(P3, C, M),
    connected(P3, P2, M, [P3|Visited]).

adjacent(p(X,Y1), p(X,Y2)) :- Y2 is Y1+1.
adjacent(p(X,Y1), p(X,Y2)) :- Y2 is Y1-1.
adjacent(p(X1,Y), p(X2,Y)) :- X2 is X1+1.
adjacent(p(X1,Y), p(X2,Y)) :- X2 is X1-1.

color(p(X,Y), C, M) :-
    nth1(Y, M, R),
    nth1(X, R, C).

sol(M) :-
    M = [[1,_,_,_,1],
         [2,_,_,_,_],
         [3,4,_,4,_],
         [_,_,_,_,_],
         [3,2,5,_,5]],
    connected(p(1,1), p(5,1), M, [p(1,1)]),
    connected(p(1,2), p(2,5), M, [p(1,2)]),
    connected(p(1,3), p(1,5), M, [p(1,3)]),
    connected(p(2,3), p(4,3), M, [p(2,3)]),
    connected(p(3,5), p(5,5), M, [p(3,5)]).

示例查询:

?- sol(M).
M = [[1, 1, 1, 1, 1],
     [2, 2, 2, 2, 2], 
     [3, 4, 4, 4, 2],
     [3, 2, 2, 2, 2], 
     [3, 2, 5, 5, 5]].

【讨论】:

  • 使用maplist(dif(P3),Visited)而不是\+ member(P3,Visited)来保留logical-purity怎么样?
  • 好建议!我什至不知道这个结构。它现在更具声明性。
  • s(X): 直到去年我才知道这件事,左右。没什么大不了的,但它有点聪明,并且(至少)与swi-prologsicstus-prologyap一起工作是开箱即用的。
  • 顺便说一句...您是否考虑过添加基于clpfd 的独立第二个答案?我真的很想知道“old school Prolog”和“nu school Prolog”解决方案的性能——与不同的问题实例进行正面比较,从简单、中等、困难到困难......
  • 图片从here被盗。我不会添加基于 clpfd 的解决方案,因为我不知道它是如何工作的。我还有很多需要学习的地方。欢迎您尝试 clpfd 方法。
【解决方案2】:

声明式 Prolog 的“操作方式”基于非确定性,通过深度优先搜索实现。让我们来解决这个难题:M 是游乐场,一个由空闲单元(变量)或整数(颜色)组成的列表

one_step(M) :-
  cell(M, X,Y, C),
  integer(C), % the selected cell is a color
  delta(X,Y,X1,Y1),
  cell(M, X1,Y1, C). % bind adjacent to same color - must be free

cell(M, X,Y, C) :- nth1(Y,M,R), nth1(X,R,C).

% moves
delta(X,Y,X1,Y) :- X1 is X+1. % right
delta(X,Y,X1,Y) :- X1 is X-1. % left
delta(X,Y,X,Y1) :- Y1 is Y-1. % up
delta(X,Y,X,Y1) :- Y1 is Y+1. % down

这是做什么的?让我们在 3x3 操场上试试吧

?- M=[[_,9,_],[_,0,_],[_,_,9]],one_step(M).
M = [[_G1824, 9, 9], [_G1836, 0, _G1842], [_G1848, _G1851, 9]] ;
M = [[9, 9, _G1830], [_G1836, 0, _G1842], [_G1848, _G1851, 9]] ;
M = [[_G1824, 9, _G1830], [_G1836, 0, 0], [_G1848, _G1851, 9]] ;
M = [[_G1824, 9, _G1830], [0, 0, _G1842], [_G1848, _G1851, 9]] ;
M = [[_G1824, 9, _G1830], [_G1836, 0, _G1842], [_G1848, 0, 9]] ;
M = [[_G1824, 9, _G1830], [_G1836, 0, _G1842], [_G1848, 9, 9]] ;
M = [[_G1824, 9, _G1830], [_G1836, 0, 9], [_G1848, _G1851, 9]] ;
false.

无需声明网格大小、检查索引边界等...当 one_step/1 成功时,它实例化一个空闲单元格到相邻的相同颜色...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2011-06-10
    • 2020-04-03
    相关资源
    最近更新 更多