【发布时间】:2017-10-20 13:26:27
【问题描述】:
我正在为自己制作的原创 4 人棋盘游戏创建 AI。
有关棋盘游戏的详细信息:
4 名玩家轮流在四个主要方向之一同时移动他们的彩色棋子。棋子可以移出棋盘。开始时每个玩家都有 5 条生命。每移出一块棋子,玩家就会失去 1 条生命。新棋子将在整个游戏中确定地生成。
我查找了如何执行极小极大算法并找到了this。我通读了一遍,认为我理解了所有内容,因此我尝试将第 1.5 节中的 Java 代码翻译成 Swift。
这是我的思考过程:
- 由于我的游戏有 4 个玩家,我会将其他所有人视为最小化玩家。
- 在 Java 代码中,有一行撤消了移动。由于我的游戏的游戏状态在每次移动时都会发生巨大变化,因此我只需将所有游戏状态存储在一个数组中,当需要撤消某些操作时,我可以在数组上调用
dropLast。 - 由于我的游戏中的移动表示为
Direction枚举,如果像 Java 代码这样的 int 数组,我将返回一个(Int, Direction)元组。 -
game是一个计算属性,它只返回gameStates.last! -
每次我在
game上调用moveUp/Down/Left/Right方法之一时,game.currentPlayer都会发生变化,因此我不需要编写额外的代码来决定谁是下一个玩家。 - 在最后一行,我需要返回
(bestScore, bestDirection),但我意识到有时bestDirection没有被赋值。因此,我将bestDirection设为可选。如果没有在return语句中赋值,我就返回任意方向。
这是我的尝试:
private func minimax(depth: Int, color: Color) -> (score: Int, direction: Direction) {
var bestScore = color == myColor ? Int.min : Int.max
var currentScore: Int
var bestDirection: Direction?
if game.players.filter({$0.lives > 0}).count < 2 || depth == 0 {
// This is a call to my heuristic evaluation function
bestScore = evaluateHeuristics()
} else {
// if the player has no pieces on the board, just move up since moving in any direction won't change anything
for move in (game.board.indicesOf(color: color).count == 0 ? [Direction.up] : [Direction.up, .down, .left, .right]) {
let gameCopy = game.createCopy()
switch move {
case .up: gameCopy.moveUp()
case .down: gameCopy.moveDown()
case .left: gameCopy.moveLeft()
case .right: gameCopy.moveRight()
}
gameStates.append(gameCopy)
// myColor is like mySeed in the original Java code
if color == myColor {
currentScore = minimax(depth: depth - 1, color: game.currentPlayer.color).score
if currentScore > bestScore {
bestScore = currentScore
bestDirection = move
}
} else {
currentScore = minimax(depth: depth - 1, color: game.currentPlayer.color).score
if currentScore < bestScore {
bestScore = currentScore
bestDirection = move
}
}
_ = gameStates.dropLast()
}
}
return (bestScore, bestDirection ?? .left)
}
当我用 4 的 depth 测试这个 AI 时,它似乎要么做出愚蠢的动作,比如将他的棋子移出棋盘,要么只将他的棋子朝一个方向移动。
我还注意到,当递归调用返回时,gameStates 的长度约为 90。通常它应该是1对吗?因为在递归调用返回时,AI 尝试的所有动作都应该已经撤消,而gameStates 将只包含初始状态。
我做错了什么?
【问题讨论】:
-
我不相信这段代码会编译。
minimax被声明为返回一个元组(score: Int, direction: Direction),但您将结果分配给Int。 -
另外,除非我误解了游戏规则,否则移动应该包含一个方向列表,玩家仍然拥有的每个棋子对应一个方向,但您只是返回一个方向。
-
@JeremyP 不,我在该行的最后访问了
.score元素。 -
啊,好吧,代码框在错误的地方截断了线路!
-
我说的是“同时”,所以所有的棋子都朝一个方向移动,可以是左上下也可以是右上。
标签: swift artificial-intelligence minimax