Swift 4 - GKMinmaxStrategist Modifying Actual Game Model

67 views Asked by At

Before I start, this question has already been asked a while ago but I don't believe the answer is satisfactory (GKMinmaxStrategist modifies model after return of best move)

I am trying to build a straightforward board game with two player types (king, enemy). As part of that I am trying to implement the GKMinmaxStrategist and the problem is that it keeps modifying the actual game model rather than simulating moves on the copy.

Let me start by showing some code:

    //From Board Class
    func moveToken(move: Move) {
        let tokenAtOrigin = tokenAt(at: move.origin)
        gameBoard[move.destination.row, move.destination.column] = tokenAtOrigin
        tokenAtOrigin?.row = move.destination.row
        tokenAtOrigin?.column = move.destination.column
        gameBoard[move.origin.row, move.origin.column] = nil
    }

    //Extension to Board for strategist implementation
    extension Board: GKGameModel {

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

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

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

    //GameViewController
    var board = Board()
    strategist.gameModel = board
    ...

As mentioned in the code above, copy and self turn out to be separate instances. Im fairly certain the problem is in the apply method where moveToken(move: move) is being applied to the actual game board rather than the copy, but I don't understand why (To confirm I have printed the game board just after entering and just before exiting the function and the prints differed, whereas I wouldn't expect the main board to change whenever this method is called). Otherwise it seems to work fine and it returns a sensible move.

Any help would be much appreciated!

1

There are 1 answers

3
Sam On BEST ANSWER

I suspect the problem is in your setGameModel function:

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

My guess is that board.gameBoard is a class and not a struct, which means both game models reference the same board. Then, when the GKMinmaxStrategist does its computation, it changes that class and therefore the current game model.

Hope this helps!