IPVGO: Prevent issues caused by resetting the board while the go AI is in flight (#1608)

This commit is contained in:
Michael Ficocelli
2024-09-07 21:33:49 -04:00
committed by GitHub
parent 4f426e1b20
commit 2a5b0ca4e9
6 changed files with 32 additions and 10 deletions
+25 -5
View File
@@ -34,18 +34,22 @@ export function makeAIMove(boardState: BoardState, useOfflineCycles = true): Pro
return Go.nextTurn;
}
isAiThinking = true;
let encounteredError = false;
// If the AI is disabled, simply make a promise to be resolved once the player makes a move as white
if (boardState.ai === GoOpponent.none) {
GoEvents.emit();
// Update currentTurnResolver to call Go.nextTurn's resolve function with the last played move's details
Go.nextTurn = new Promise((resolve) => (currentTurnResolver = () => resolve(getPreviousMoveDetails())));
resetAI();
}
// If an AI is in use, find the faction's move in response, and resolve the Go.nextTurn promise once it is found and played.
else {
const currentMoveCount = Go.currentGame.previousBoards.length;
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai, useOfflineCycles).then(
async (play): Promise<Play> => {
if (boardState !== Go.currentGame) return play; //Stale game
if (boardState !== Go.currentGame) {
//Stale game
encounteredError = true;
return play;
}
// Handle AI passing
if (play.type === GoPlayType.pass) {
@@ -59,6 +63,13 @@ export function makeAIMove(boardState: BoardState, useOfflineCycles = true): Pro
// Handle AI making a move
await waitCycle(useOfflineCycles);
if (currentMoveCount !== Go.currentGame.previousBoards.length || boardState !== Go.currentGame) {
console.warn("AI move attempted, but the board state has changed.");
encounteredError = true;
return play;
}
const aiUpdatedBoard = makeMove(boardState, play.x, play.y, GoColor.white);
// Handle the AI breaking. This shouldn't ever happen.
@@ -75,13 +86,22 @@ export function makeAIMove(boardState: BoardState, useOfflineCycles = true): Pro
// Once the AI moves (or the player playing as white with No AI moves),
// clear the isAiThinking semaphore and update the board UI.
Go.nextTurn = Go.nextTurn.finally(() => {
isAiThinking = false;
if (!encounteredError) {
isAiThinking = false;
}
GoEvents.emit();
});
return Go.nextTurn;
}
export function resetAI(thinking = true) {
isAiThinking = thinking;
GoEvents.emit();
// Update currentTurnResolver to call Go.nextTurn's resolve function with the last played move's details
Go.nextTurn = new Promise((resolve) => (currentTurnResolver = () => resolve(getPreviousMoveDetails())));
}
/**
* Resolves the current turn.
* This is used for players manually playing against their script on the no-ai board.