首页 > 解决方案 > GKMinmaxStrategist - 不适用于开始移动(Swift 4)

问题描述

我正在开发一个两人战略棋盘游戏,可以选择与 CPU 对战,我正在使用 GKMinmaxStrategist 为 CPU 玩家提供一些大脑。仅作为背景,游戏中有两个“派系”(国王,敌人) 玩国王的人总是开始。

现在,我已经设法实现了策略师,如果我与 CPU 对战 King 并迈出第一步,它就会起作用。但是,当我扮演 Enemy 并且 CPU 必须迈出第一步(扮演 King)时,它的工作方式并不奇怪。看起来,在调用了策略师的 bestMove 方法之后,它并没有调用任何底层的模拟方法,比如 isWin、apply、score 等。

我曾尝试更改规则,让敌人总是开始,但它再次不起作用,而当我扮演国王并迈出第一步时,它确实为敌人吐出动作(如上所述)。

此外,我没有使用策略师,而是简单地随机选择了移动(所有可能的移动),只是为了看看基于回合的逻辑是否有效,并且确实有效。对于这两个派系,它会在我期望的时间和方式移动。

所以这第一步,无论哪个派系似乎都是问题,我不知道为什么会这样。有没有人遇到过类似的问题,或者是否有人对为什么会出现这种情况有任何好主意?

任何帮助将非常感激。

这是游戏模型的扩展,包括战略家以及管理游戏玩法的 GameVC。

extension Board: GKGameModel {
    var activePlayer: GKGameModelPlayer? {
        return currentPlayer
    }

    var players: [GKGameModelPlayer]? {
        return Player.allPlayers
    }

    func copy(with zone: NSZone? = nil) -> Any {
        let copy = Board()
        copy.setGameModel(self)
        return copy
    }

    func setGameModel(_ gameModel: GKGameModel) {
        if let board = gameModel as? Board {
            tokens = board.tokens
        }
    }

    func isWin(for player: GKGameModelPlayer) -> Bool {
        guard let player = player as? Player else {
            return false
        }
        if let winner = isWinner() {
            return player.player == winner
        } else {
            return false
        }
    }

    func gameModelUpdates(for player: GKGameModelPlayer) -> [GKGameModelUpdate]? {
        guard let player = player as? Player else {
            return nil
        }
        if isWin(for: player) {
            return nil
        }
        return allPossibleMoves(faction: player.player)
    }

    func apply(_ gameModelUpdate: GKGameModelUpdate) {
        guard  let move = gameModelUpdate as? Move else {
            return
        }
        performMove(move: move)
        currentPlayer = currentPlayer.opponent
    }

    func score(for player: GKGameModelPlayer) -> Int {
        guard let player = player as? Player else {
            return Score.none.rawValue
        }
        if isWin(for: player) {
            return Score.win.rawValue
        } else {
            return Score.none.rawValue
        }
    }
}```

```class GameViewController: UIViewController, BoardDelegate {

    var scene: GameScene!
    var board: Board!
    var strategist: GKMinmaxStrategist!

    override func loadView() {
        self.view = SKView(frame: UIScreen.main.bounds)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        let skView = view as! SKView
        skView.isMultipleTouchEnabled = false
        skView.isUserInteractionEnabled = false
        scene = GameScene(size: skView.bounds.size)
        scene.scaleMode = .aspectFill
        board = Board()
        board.delegate = self
        scene.board = board
        scene.handleUserMove = handleUserMove
        scene.fillBoardWithSprites()
        strategist = GKMinmaxStrategist()
        strategist.maxLookAheadDepth = 1
        strategist.randomSource = GKARC4RandomSource()
        strategist.gameModel = board
        skView.presentScene(scene)
        initiateMove()
    }

    //Check if user`s turn
    func checkUserTurn() -> Bool {
        return board.userPlayer.player == board.currentPlayer.player
    }

    //Change turn of players between user and CPU
    func changeTurn() {
        board.currentPlayer = board.currentPlayer.opponent
    }

    //Find best move for CPU using GKMinmaxStrategist
    func chooseCpuMove() -> Move? {
        if let move = strategist.bestMove(for: board.currentPlayer) as? Move {
            print("found move")
            return move
        }
        return nil
    }

    //Perform CPU move
    func handleCpuMove(move: Move) {
        scene.animateMove(move: move) {}
        board.performMove(move: move)
        board.moved()
    }

    //Check whose turn it is and either turn on user interaction or start CPU move
    func initiateMove() {
        print("initiating")
        self.view.isUserInteractionEnabled = checkUserTurn()
        if checkUserTurn() {
            //Wait for user to move
        } else {
            print("checking cpuMove")
            if let cpuMove = chooseCpuMove() {
                handleCpuMove(move: cpuMove)
            }
        }
    }

    func handleUserMove(move: Move, bool: Bool) {
        if board.isMoveAllowed(move: move) {
            scene.animateMove(move: move) {}
            board.performMove(move: move)
            board.moved()
        }
    }

    func currentPlayerDidMove(board: Board) {
        changeTurn()
        if board.isWinner() != nil {
            board.endGame()
        } else {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                self.initiateMove()
            }
        }
    }

    func gameDidEnd(board: Board) {
        self.view.isUserInteractionEnabled = false
        UserDefaults.standard.set(board.currentPlayer.player.name, forKey: "winner")
        AppDelegate.shared.rootViewController.gameOverScreen()
    }
}```

标签: swiftgameplay-kitgkminmaxstrategist

解决方案


推荐阅读