GKMinmaxStrategist不会返回任何动作

时间:2016-01-05 16:44:43

标签: swift gameplay-kit gkminmaxstrategist

我的main.swift中有以下代码:

let strategist = GKMinmaxStrategist()
strategist.gameModel = position
strategist.maxLookAheadDepth = 1
strategist.randomSource = nil

let move = strategist.bestMoveForActivePlayer()

...其中position是我的GKGameModel子类Position的实例。运行此代码后,movenilbestMoveForPlayer(position.activePlayer!)也会产生nil(但position.activePlayer!会产生Player个对象。

然而,

let moves = position.gameModelUpdatesForPlayer(position.activePlayer!)!

导致非空数组的可能移动。从Apple的文档(约bestMoveForPlayer(_:)):

  

如果玩家无效,玩家不是游戏模型的一部分,或玩家没有有效的移动,则返回nil。

据我所知,情况并非如此,但函数仍会返回nil。可能会发生什么?

如果它有任何帮助,这是我对GKGameModel协议的实现:

var players: [GKGameModelPlayer]? = [Player.whitePlayer, Player.blackPlayer]
var activePlayer: GKGameModelPlayer? {
    return playerToMove
}

func setGameModel(gameModel: GKGameModel) {
    let position = gameModel as! Position
    pieces = position.pieces
    ply = position.ply
    reloadLegalMoves()
}

func gameModelUpdatesForPlayer(thePlayer: GKGameModelPlayer) -> [GKGameModelUpdate]? {
    let player = thePlayer as! Player
    let moves = legalMoves(ofPlayer: player)
    return moves.count > 0 ? moves : nil
}

func applyGameModelUpdate(gameModelUpdate: GKGameModelUpdate) {
    let move = gameModelUpdate as! Move
    playMove(move)
}

func unapplyGameModelUpdate(gameModelUpdate: GKGameModelUpdate) {
    let move = gameModelUpdate as! Move
    undoMove(move)
}

func scoreForPlayer(thePlayer: GKGameModelPlayer) -> Int {
    let player = thePlayer as! Player
    var score = 0
    for (_, piece) in pieces {
        score += piece.player == player ? 1 : -1
    }
    return score
}

func isLossForPlayer(thePlayer: GKGameModelPlayer) -> Bool {
    let player = thePlayer as! Player
    return legalMoves(ofPlayer: player).count == 0
}

func isWinForPlayer(thePlayer: GKGameModelPlayer) -> Bool {
    let player = thePlayer as! Player
    return isLossForPlayer(player.opponent)
}

func copyWithZone(zone: NSZone) -> AnyObject {
    let copy = Position(withPieces: pieces.map({ $0.1 }), playerToMove: playerToMove)
    copy.setGameModel(self)
    return copy
}

如果还有其他代码我应该展示,请告诉我。

3 个答案:

答案 0 :(得分:3)

您需要在应用取消应用移动后更改activePlayer。 在您的情况下,playerToMove

  

轮到玩家对游戏模型进行更新的玩家。 GKMinmaxStrategist假设下一次调用applyGameModelUpdate:方法将代表此播放器执行移动。

,当然还有:

  

功能applyGameModelUpdate将GKGameModelUpdate应用于游戏模型,可能会产生新的activePlayer。 GKMinmaxStrategist将在主游戏模型的副本上调用此方法,以推测未来可能的移动及其影响。假设调用此方法代表activePlayer属性标识的播放器执行移动。

func applyGameModelUpdate(gameModelUpdate: GKGameModelUpdate) {
    let move = gameModelUpdate as! Move
    playMove(move)

    //Here change the current Player
    let player = playerToMove as! Player
    playerToMove = player.opponent
}

unapplyGameModelUpdate实施也是如此。

另外,请特别注意setGameModel实施,因为它应该复制模型中的所有数据。这包括activePlayer

  

设置其他游戏模型的数据。应复制所有数据,并且不应保留指向复制的游戏状态的任何指针。 GKMinmaxStrategist使用它来处理游戏的排列,而无需对主要游戏模型应用潜在的破坏性更新。

答案 1 :(得分:0)

我遇到了同样的问题。事实证明,.activePlayer必须返回.players返回的其中一个实例。仅返回匹配.playerId的新实例是不够的。

答案 2 :(得分:0)

简单的清单:

  1. GKMinmaxStrategist 的 .bestMove(for:) 被调用
  2. GKMinmaxStrategist 的 .gameModel 已设置
  3. GKGameModel 的 isWin(for:) 未在移动前返回 true
  4. GKGameModel 的 isLoss(for:) 未在移动前返回 true
  5. GKGameModel 的 gameModelUpdates(for:) 不会一直返回 nil
  6. GKGameModel 的 score(for:) 已实现