I am using swift to develop a chess game. When the computer is playing itself, the display does not get updated when a move completed until it is out of the loop (in this case the game is ended).
I have tried to dispatch it in a background queue to generate a move and dispatch it back to main queue to make the move and update the display. While it seems to help updating the display, but I have no way to predict the completion of each background queue. That messes up the order of the moves.
Is there a better way to make computer playing itself and properly update the display after each move is completed?
while chessGame.checkmate != true {
DispatchQueue.global(qos: .background).async {
let bestMove = chessAI.findBestMove(depth : chessGame.searchDepth)
if bestMove != nil {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
chessMove.makeMove(m : bestMove!)
self.boardView.setNeedsDisplay()
}
} else {
print("CheckMate!")
chessGame.checkmate = true
}
}
}
You can force display immediately (by calling displayIfNeeded
), but it won't help.
The problem is that the while
loop does not pause between iterations: it just keeps looping at top speed. Thus the while
loop is a poor strategy.
Instead, use recursion. This puts control of when to do the next iteration in your hands, namely, you recurse after a delay. That is a loop where you get to pause between iterations.
Pseudocode:
func nextMove() {
DispatchQueue.global(qos: .background).async {
let bestMove = chessAI.findBestMove(depth : chessGame.searchDepth)
if bestMove != nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // or whatever
chessMove.makeMove(m : bestMove!)
self.boardView.setNeedsDisplay()
if chessGame.checkmate != true {
nextMove()
} else {
print("checkmate")
}
}
}
}
}