我正在使用SWI 7.2.3并拥有以下程序:
?-use_module(library(clpfd)).
:- dynamic size/2,wall/2.
in_board(X,Y):-X #> 0,Y #> 0,size(N,M),X #=< N,Y #=< M.
wall_exists_line(X,Y,W) :- wall(X,Z),(Y #=< Z,W #=< Y;Y#=< W,Z#=< Y).
wall_not_exists_line(X,Y,W) :- not(wall_exists_line(X,Y,W)).
same_line(X,Y,Z,W):- X #= Z,in_board(Z,W),in_board(X,Y),wall_not_exists_line(X,Y,W).
我在这里使用约束编程因为我希望in_board
能够工作,即使X
和Y
都没有实例化(是的,我知道它可以通过其他方式实现,但我发现这更容易)。
正如您所看到的,size,wall
是动态的,并且基本上都是整数。
我的问题是,如果我断言size(4,4)
和wall(2,2)
并查询same_line(X,1,Y,3)
,则当它返回X = Y, X in 1\/3..4
(或类似)时,它会返回false。
我知道not(something(X))
的意思是“没有X存在于哪里是真的”,我想“存在X,其中某些东西(X)不是真的”(通过我实际上意为wall_exists_line
的东西)。
我尝试使用forall
但是forall对于this问题中所述的约束不起作用。
我可以找到针对我的特定问题的解决方案但是我更喜欢一般的答案,即如何处理forall
正常做的约束?
上面的程序只是prolog程序的一个子集,它应该解决akari游戏(也称为点亮,参见game),需要谓词same_line
来确定哪些单元格是通过一些光线减轻。
size(N,M)
表示我们的论坛有N
行和M
列,wall(X,Y)
表示单元格(X,Y)
是一堵墙。
之前我没有wall_not_exists_line
,我将not(wall_exists_line)
直接放在same_line
中,我认为引入单独的谓词可以解决它,但事实并非如此。
我想到将wall_exists_line
改为对它的否定,q and p
的否定是not(q) or not(p)
所以wall_exists_line
会改变为:
wall_not_exists_line(X,Y,W) :- not(wall(X,Z));(not(Y #=<Z);not(W #=<Y)),(not(Y#=<W);not(Z#=<Y)).
不幸的是not(wall(X,Z))
表示“没有X或Z存在哪个墙(X,Z)是真的”,我不希望这个,因为wall
是动态的我不能做任何事情它
答案 0 :(得分:0)
我找到了解决方案。
not(wall_exists_line(X,Y,W))
会检查X
以及Y
和W
的每个值,如果他们没有固定值。
in_board(X,Y)
在时间间隔内约束X
和Y
但不是固定值,因此not
会尝试间隔中的每个值。
解决方案是在输入X,Y,W
之前实例化变量not
,这可以通过将in_board
更改为此来完成:
in_board(X,Y):-size(N,M),between(0,N,X),between(0,M,Y).
这种方式between
将实例化X
和Y
,幸运的是between
会提供区间中的所有值。
clpfd和just between
之间的主要区别在于clpfd在between
时返回域 - 如果第三个参数未被实例化 - 返回两个值之间的每个值。