Recursion 如何在Prolog中的递归函数中使用动态列表
我有一个动态列表,存储字段坐标和该字段的所有者Recursion 如何在Prolog中的递归函数中使用动态列表,recursion,prolog,alpha-beta-pruning,Recursion,Prolog,Alpha Beta Pruning,我有一个动态列表,存储字段坐标和该字段的所有者 :-dynamic board/2. 此列表中的一个条目如下所示: board(e4,[w]). 还有22个董事会职位看起来都很相似 我正在尝试为棋盘的游戏实现AI。 我正在使用alpha-beta算法,因此必须创建新的“板”来评估这种情况 我有一份原始董事会的副本要处理,但现在有一个功能,可以根据当前的移动调整董事会,如下所示: move(position,boardOld,boardNew) starting_board([[b-
:-dynamic
board/2.
此列表中的一个条目如下所示:
board(e4,[w]).
还有22个董事会职位看起来都很相似
我正在尝试为棋盘的游戏实现AI。
我正在使用alpha-beta算法,因此必须创建新的“板”来评估这种情况
我有一份原始董事会的副本要处理,但现在有一个功能,可以根据当前的移动调整董事会,如下所示:
move(position,boardOld,boardNew)
starting_board([[b-r, b-b, b-n, b-q, b-k, b-n, b-b, b-r],
[b-p, b-p, b-p, b-p, b-p, b-p, b-p, b-p],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[w-p, w-p, w-p, w-p, w-p, w-p, w-p, w-p],
[w-r, w-b, w-n, w-q, w-k, w-n, w-b, w-r]]).
这被称为递归,因此在第二次调用boardOld等于boardNew,而boardNew是分析中具有下一步的oldBoard
我的想法是在每次迭代中复制旧板,但我不知道如何这样做
copy_predicate_clauses(boardOld(A,B),boardNew(A,B)).
将旧板添加到新板,因为列表已存在
我正在使用以下算法(无法复制,因为它是图像):
PDF第445页(书籍第407页)
该算法在初始化时将位置获取为“Board”,我不知道如何使用我的列表执行此操作,此外,move子句(move,Position,Position1)返回带有当前移动的新板。这被称为递归,我不知道如何在不覆盖以前的板的情况下为position1创建板
编辑//
好的,我明白了。但我已经在游戏中大量使用了这个谓词,我不想完全改变它。我这样做:
findall((X,Y),board(X,Y),CurrentBoard).
CurrentBoard给了我一个这样的列表
[(e4,[w,w]),(g4,[s,w]),(b7,[r,w,s])]
现在我不能用我的方法来决定可能的行动
我有这样的事实
move(e4,d5).
move(d5,e6).
说明哪些移动(从,到)是可能的,现在我尝试了这个
findall((X,Y),listMoves(CurrentBoard,X,Y),possibleMoves).
用这样的东西。我在这一点上苦苦挣扎。如何生成包含可能移动的列表。我必须以某种方式从currentBoard获得X坐标,检查该坐标(该坐标上的棋子)列表的标题是否属于我,并检查Y坐标(to)是否自由
listMoves([Coordinate|[Head|Tail]], X, Y) :-
move(X,Y),
ownField(X,Coordinate,Head),
如果您阅读(打印)第401页,作者将基本游戏算法概述如下:
本节其余部分使用“位置”一词的方式让我相信它们指的是整个游戏状态。对于像国际象棋这样的游戏,这将是棋盘本身的状态:棋子在哪里
在此基础上,作者继续讨论了move/2
和move/3
,这两个定义如下:
通过choose_move/3
可以方便地将move的选择与move/3的执行分开
然后在第403页
如果move
可能从当前位置移动,则谓词move(Position,move)
为真
综上所述,这一切都向我表明,他们希望一个位置
是完整的棋盘(我认为你在下棋,是吗?)和移动
是合法的移动,以便定义移动/2
,然后移动/3
就是移动/2
,返回结果棋盘。换句话说,最初的棋盘可能看起来像这样:
move(position,boardOld,boardNew)
starting_board([[b-r, b-b, b-n, b-q, b-k, b-n, b-b, b-r],
[b-p, b-p, b-p, b-p, b-p, b-p, b-p, b-p],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil, nil, nil, nil],
[w-p, w-p, w-p, w-p, w-p, w-p, w-p, w-p],
[w-r, w-b, w-n, w-q, w-k, w-n, w-b, w-r]]).
这就是我可以设置它的方式;毫无疑问,可能有更有效或更明智的方法,但关键是,您的位置
值应始终包含董事会的整个状态,如下所示。事实上,它可能需要包括其他信息,比如轮到谁了,或者如果你想记录每个动作,你也可以把它放在那里
从这里,您可以编写move/2
和move/3
。我倾向于(出于说教的目的)只写move/3
,并用它来构建move/2
,但为了提高效率,您可能需要单独完成它们。我下棋已经够差了,我就到此为止(我不相信你会下棋)。但基本上,你想看到的是move(StartPosition,move,NewPosition)
,给定一个起始位置,将move
与移动的某种简短描述相结合,并在移动后将NewPosition
与整个电路板状态相结合,因此你会得到一个前后快照
一旦你有了这些部件,我想你可以按原样使用书籍代码
我认为你基本上有一些误解:
由于缺乏详细信息,这很难回答(如果不是不可能的话)。我将编辑此问题并分享更多详细信息。您的问题是,您试图将动态存储视为列表(您自己这么说,但
board/2
是一个谓词,而不是一个列表),它并不真正适合此目的。你最好为你的董事会状态创建明确的列表并传递它们,因为在动态存储中操作实际列表要比操作事实容易得多。我带着一些想法编辑了我的线程……但在序言中,再次尝试possibleMoves
是一个原子,而不是一个变量。:)