mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-17 13:13:49 +01:00
IPVGO: Prevent issues caused by resetting the board while the go AI is in flight (#1608)
This commit is contained in:
parent
4f426e1b20
commit
2a5b0ca4e9
@ -31,5 +31,5 @@ export interface Go
|
||||
| [makeMove(x, y)](./bitburner.go.makemove.md) | Make a move on the IPvGO subnet game board, and await the opponent's response. x:0 y:0 represents the bottom-left corner of the board in the UI. |
|
||||
| [opponentNextTurn(logOpponentMove)](./bitburner.go.opponentnextturn.md) | Returns a promise that resolves with the success or failure state of your last move, and the AI's response, if applicable. x:0 y:0 represents the bottom-left corner of the board in the UI. |
|
||||
| [passTurn()](./bitburner.go.passturn.md) | <p>Pass the player's turn rather than making a move, and await the opponent's response. This ends the game if the opponent passed on the previous turn, or if the opponent passes on their following turn.</p><p>This can also be used if you pick up the game in a state where the opponent needs to play next. For example: if BitBurner was closed while waiting for the opponent to make a move, you may need to call passTurn() to get them to play their move on game start.</p> |
|
||||
| [resetBoardState(opponent, boardSize)](./bitburner.go.resetboardstate.md) | <p>Gets new IPvGO subnet with the specified size owned by the listed faction, ready for the player to make a move. This will reset your win streak if the current game is not complete and you have already made moves.</p><p>Note that some factions will have a few routers on the subnet at this state.</p><p>opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????" or "No AI",</p> |
|
||||
| [resetBoardState(opponent, boardSize)](./bitburner.go.resetboardstate.md) | <p>Gets new IPvGO subnet with the specified size owned by the listed faction, ready for the player to make a move. This will reset your win streak if the current game is not complete and you have already made moves.</p><p>Note that some factions will have a few routers already on the subnet after a reset.</p><p>opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????" or "No AI",</p> |
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
Gets new IPvGO subnet with the specified size owned by the listed faction, ready for the player to make a move. This will reset your win streak if the current game is not complete and you have already made moves.
|
||||
|
||||
Note that some factions will have a few routers on the subnet at this state.
|
||||
Note that some factions will have a few routers already on the subnet after a reset.
|
||||
|
||||
opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????" or "No AI",
|
||||
|
||||
|
@ -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.
|
||||
|
@ -4,7 +4,7 @@ import { Player } from "@player";
|
||||
import { AugmentationName, GoColor, GoOpponent, GoPlayType, GoValidity } from "@enums";
|
||||
import { Go, GoEvents } from "../Go";
|
||||
import { getNewBoardState, makeMove, passTurn, updateCaptures, updateChains } from "../boardState/boardState";
|
||||
import { makeAIMove } from "../boardAnalysis/goAI";
|
||||
import { makeAIMove, resetAI } from "../boardAnalysis/goAI";
|
||||
import {
|
||||
evaluateIfMoveIsValid,
|
||||
getControlledSpace,
|
||||
@ -292,6 +292,7 @@ export function resetBoardState(
|
||||
}
|
||||
|
||||
Go.currentGame = getNewBoardState(boardSize, opponent, true);
|
||||
resetAI(false);
|
||||
GoEvents.emit(); // Trigger a Go UI rerender
|
||||
logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`);
|
||||
return simpleBoardFromBoard(Go.currentGame.board);
|
||||
|
@ -18,7 +18,7 @@ import { GoScoreModal } from "./GoScoreModal";
|
||||
import { GoGameboard } from "./GoGameboard";
|
||||
import { GoSubnetSearch } from "./GoSubnetSearch";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { makeAIMove, resolveCurrentTurn } from "../boardAnalysis/goAI";
|
||||
import { makeAIMove, resetAI, resolveCurrentTurn } from "../boardAnalysis/goAI";
|
||||
import { GoScoreExplanation } from "./GoScoreExplanation";
|
||||
|
||||
interface GoGameboardWrapperProps {
|
||||
@ -144,6 +144,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
||||
}
|
||||
|
||||
Go.currentGame = getNewBoardState(newBoardSize, newOpponent, true);
|
||||
resetAI(false);
|
||||
rerender();
|
||||
resolveCurrentTurn();
|
||||
}
|
||||
|
2
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
2
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -4597,7 +4597,7 @@ export interface Go {
|
||||
* This will reset your win streak if the current game is not complete and you have already made moves.
|
||||
*
|
||||
*
|
||||
* Note that some factions will have a few routers on the subnet at this state.
|
||||
* Note that some factions will have a few routers already on the subnet after a reset.
|
||||
*
|
||||
* opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????" or "No AI",
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user