I have the following code in my main.swift:
let strategist = GKMinmaxStrategist()
strategist.gameModel = position
strategist.maxLookAheadDepth = 1
strategist.randomSource = nil
let move = strategist.bestMoveForActivePlayer()
...where position is an instance of my GKGameModel subclass Position. After this code is run, move is nil. bestMoveForPlayer(position.activePlayer!) also results in nil (but position.activePlayer! results in a Player object).
However,
let moves = position.gameModelUpdatesForPlayer(position.activePlayer!)!
results in a non-empty array of possible moves. From Apple's documentation (about bestMoveForPlayer(_:)):
Returns nil if the player is invalid, the player is not a part of the game model, or the player has no valid moves available.
As far as I know, none of this is the case, but the function still returns nil. What could be going on here?
If it can be of any help, here's my implementation of the GKGameModel protocol:
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
}
If there's any other code I should show, let me know.
simple checklist:
.bestMove(for:)is called.gameModelis setisWin(for:)does not return true before moveisLoss(for:)does not return true before movegameModelUpdates(for:)does not return nil all the timescore(for:)is implemented