首先,我建议将您的问题分解为更小的部分。您应该有一个制作随机坐标的过程:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
其次,你的checkCoordinate/3
正在将 Prolog 的成功/失败转换为整数,这对 Prolog 来说只是忙碌的工作,并没有真正改善你的生活。memberchk/2
完全足以完成您的任务(member/2
也可以工作,但比必要的更强大)。这里真正的问题不是这个member/2
不起作用,而是您试图在退出时建立此列表参数,但您需要它在进入时存在才能检查它。
我们通常通过添加第三个参数并在过程中将值添加到列表中来解决 Prolog 中的此类问题。然后,基本情况将该列表与出站列表等同,并且我们使用较低数量的过程来保护整个列表。换句话说,我们这样做:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
现在我们有两件事,memberchk/2
应该按照我们需要的方式工作:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
这似乎符合我们的要求:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
最后,我注意到您继续使用以下语法:N is 1, ...
。我警告你,这对我来说看起来像是一个错误,因为这和N = 1
,你的谓词可能会有点令人厌烦地这样表述:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
我的倾向是通过计算来完成char_code/2
但这种结构实际上可能更好。
另一个提示您做错的事情是参数L
to createCoordinates/2
在所有情况下都会被传递,并且在任何情况下都不会被检查。在 Prolog 中,我们经常会看到看似毫无意义地传递的变量,但它们通常会改变位置或多次使用,如random_coordinates(0, Result, Result)
;虽然那里似乎什么也没发生,但实际发生的是管道:构建的参数变成了结果值。那里的变量没有发生任何有趣的事情,但正在对其进行探索。但是代码中的 L 根本没有发生任何事情,除了据说正在检查新坐标之外。但你实际上从来没有向它附加任何东西,所以没有理由期望任何东西都会在 L 中结束。
Edit请注意,@lambda.xy.x 通过在子句头部添加新坐标并仅在主体中的递归调用之后检查列表来解决其答案中的问题,从而消除了对第二个列表参数的需要。
Edit 2另请查看 @lambda.xy.x 的其他解决方案,因为当 N 接近 100 时,它具有更好的时间复杂度。