SteveBarnegren / SwiftChess

Chess engine and AI written in Swift
MIT License
145 stars 35 forks source link

Reset Game #16

Closed alanpridestar closed 4 years ago

alanpridestar commented 4 years ago

First of all, your project is really impressive. Thank you for sharing it.

Secondly, if I wanted to add a reset entire game feature to the GameViewController how would you recommend going about that?

I've tried a few different things but I think I am quite close now, but can't seem to figure out why it's not working.

I decided to use your persistence feature to reset the game. When the game is initially set I saved the dictionaryRepresentation of the game in a variable, so that when I reset the game I could do game = ChessGame(dictionary: startGameRepresentation), but that did not work. So i decided to reinitialize the game with a human and AI Player (the only scenario I want) and set the current player to the human player.

After that I remove all the pieces from the board and then setup the game again with the code that you've written in your viewDidLoad(). I then use the code you set up in viewDidLayoutSubviews to layout the pieces, but once that happens I cannot move any pieces. I can click on a piece and the square behind it gets highlighted in red, but I cannot then move the piece.

The problem I'm facing now is that guard let player = game.currentPlayer as? Human else { return } always returns in the touchedSquareAtIndex delegate function

My current code is as follows

fileprivate func setupGame() { //Copy of your viewDidLoad code
    // Add initial piece views
    for location in BoardLocation.all {

        guard let piece = game.board.getPiece(at: location) else {
            continue
        }

        addPieceView(at: location.x, y: location.y, piece: piece)
    }

    // Activity Indicator
    activityIndicator.hidesWhenStopped = true

    // Update castle buttons visibility
    updateCastleButtonsVisibility()

}

func reset() {
    let whitePlayer = Human(color: .white)
    let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: gameDifficulty ?? AIConfiguration.Difficulty.medium))
    game = ChessGame(firstPlayer: whitePlayer, secondPlayer: blackPlayer)
    game.currentPlayer = whitePlayer
    boardView.subviews.forEach { (v) in
        v.removeFromSuperview()
    }
    pieceViews = []
    setupGame()

    layoutPieces()
}

fileprivate func layoutPieces() { //Copy of your layouting code in viewDidLayoutSubviews()
    // Layout pieces
    for pieceView in pieceViews {

        let gridX = pieceView.location.x
        let gridY = 7 - pieceView.location.y

        let width = boardView.bounds.size.width / 8
        let height = boardView.bounds.size.height / 8

        pieceView.frame = CGRect(x: CGFloat(gridX) * width,
                                 y: CGFloat(gridY) * height,
                                 width: width,
                                 height: height)
    }
}

Past that I can't seem to find why I can no longer interact with the game. Any help would be greatly appreciated.

Once again, thanks for the great repo.

Alan

SteveBarnegren commented 4 years ago

Hi Alan

Sorry for the delay in getting back to you!

I'm sure that you've probably either solved this by now or moved on to a different solution, but I'll answer the question anyway!

If I'm honest, I'm not sure exactly what the issue is with the code that you had at this point. I can give you some general advice on this type of issue though.

In a game, you often have some sort of state that you want to 'reset' back to how it was when you started. The thing that can catch you out is that something isn't exactly as it was in the beginning after the reset. Like you were experiencing here, you then have to try and track down which of the things you wanted to reset that is out of place, which can be a pain.

One trick to avoiding that problem is to put everything that needs to be reset under a single object that you can deallocate a reallocate. For instance, rather than having three variables that you need to reset back to their original positions, have one object that holds the three variables and then just create a brand new instance of that object. This way you know that everything is exactly how it was when you originally started.

One solution to this particular problem is to just reallocate the view controller, as this is the parent of the all of the properties that you need to reset. You might need to then put it in a parent view controller so that you have a persistent view on screen when you recreate it. That might not give you the right experience that you're looking for, but hopefully gives you the idea about how you might solve such an issue. If you want to get around that then you might be able to refactor the example implementation so that all of the state is kept under a child object that you can recreate within the view controller.

There are of course other approaches to solving these sorts of problems, but hopefully that at least points you in the right direction!