为什么我的minimax算法没有撤消每一个动作?

时间:2017-10-20 13:26:27

标签: swift artificial-intelligence minimax

我正在为我制作的原创4人桌面游戏创建AI。

有关棋盘游戏的详情:

4名玩家轮流在四个基本方向中的一个方向同时移动彩色棋子。碎片可以从板上移开。每个玩家在开始时都有5条生命。对于从棋盘上移走的每件棋子,玩家将失去1点生命。新作品将在整个游戏中确定性地产生。

我查找了如何进行minimax算法并找到了this。我仔细阅读并认为我理解了所有内容,因此我尝试将第1.5节中的Java代码翻译为Swift。

这是我的思考过程:

  • 由于我的游戏中有4名玩家,我会将其他人视为最小化玩家。
  • 在Java代码中,有一行撤消移动。由于我的游戏状态在每次移动中都会发生剧烈变化,我只会将所有游戏状态存储在一个数组中,当需要撤消某些内容时,我可以在数组上调用dropLast。 / LI>
  • 由于我的游戏中的移动被表示为Direction枚举,我将返回(Int, Direction)元组,而不是像Java代码那样的int数组。
  • game是一个只返回gameStates.last!
  • 的计算属性 每次我拨打game.currentPlayer moveUp/Down/Left/Right方法之一时,
  • game都会更改,因此我不需要编写额外的代码来决定谁是下一位球员。
  • 在最后一行,我需要返回(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只包含初始状态。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

dropLast()返回一个数组切片,其中包含除数组最后一个元素之外的所有元素。它不会修改原始数组。使用removeLast()

修改

您真正想要的是堆栈数据结构。这是一个。

public struct Stack<Element>
{
    fileprivate var elements: [Element] = []

    public init() {}

    ///    Push an element onto the top of the stack
    ///
    /// - parameter newElement: The element to push
    public mutating func push(_ newElement: Element)
    {
        elements.append(newElement)
    }

    ///    Pops the top element off the stack
    ///
    ///    - returns: The top element or nil if the stack is empty.
    public mutating func pop() -> Element?
    {
        let ret = elements.last
        if ret != nil
        {
            elements.removeLast()
        }
        return ret
    }

    ///  The top element of the stack. Will be nil if the stack is empty
    public var top: Element?
    {
        return elements.last
    }

    /// Number of items in the stack
    public var count: Int
    {
        return elements.count
    }

    /// True if the stack is empty
    public var isEmpty: Bool
    {
        return elements.isEmpty
    }
}
相关问题