mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +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. |
|
| [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. |
|
| [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> |
|
| [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.
|
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",
|
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;
|
return Go.nextTurn;
|
||||||
}
|
}
|
||||||
isAiThinking = true;
|
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 the AI is disabled, simply make a promise to be resolved once the player makes a move as white
|
||||||
if (boardState.ai === GoOpponent.none) {
|
if (boardState.ai === GoOpponent.none) {
|
||||||
GoEvents.emit();
|
resetAI();
|
||||||
// Update currentTurnResolver to call Go.nextTurn's resolve function with the last played move's details
|
|
||||||
Go.nextTurn = new Promise((resolve) => (currentTurnResolver = () => resolve(getPreviousMoveDetails())));
|
|
||||||
}
|
}
|
||||||
// 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.
|
// 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 {
|
else {
|
||||||
|
const currentMoveCount = Go.currentGame.previousBoards.length;
|
||||||
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai, useOfflineCycles).then(
|
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai, useOfflineCycles).then(
|
||||||
async (play): Promise<Play> => {
|
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
|
// Handle AI passing
|
||||||
if (play.type === GoPlayType.pass) {
|
if (play.type === GoPlayType.pass) {
|
||||||
@ -59,6 +63,13 @@ export function makeAIMove(boardState: BoardState, useOfflineCycles = true): Pro
|
|||||||
|
|
||||||
// Handle AI making a move
|
// Handle AI making a move
|
||||||
await waitCycle(useOfflineCycles);
|
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);
|
const aiUpdatedBoard = makeMove(boardState, play.x, play.y, GoColor.white);
|
||||||
|
|
||||||
// Handle the AI breaking. This shouldn't ever happen.
|
// 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),
|
// Once the AI moves (or the player playing as white with No AI moves),
|
||||||
// clear the isAiThinking semaphore and update the board UI.
|
// clear the isAiThinking semaphore and update the board UI.
|
||||||
Go.nextTurn = Go.nextTurn.finally(() => {
|
Go.nextTurn = Go.nextTurn.finally(() => {
|
||||||
|
if (!encounteredError) {
|
||||||
isAiThinking = false;
|
isAiThinking = false;
|
||||||
|
}
|
||||||
GoEvents.emit();
|
GoEvents.emit();
|
||||||
});
|
});
|
||||||
|
|
||||||
return Go.nextTurn;
|
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.
|
* Resolves the current turn.
|
||||||
* This is used for players manually playing against their script on the no-ai board.
|
* 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 { AugmentationName, GoColor, GoOpponent, GoPlayType, GoValidity } from "@enums";
|
||||||
import { Go, GoEvents } from "../Go";
|
import { Go, GoEvents } from "../Go";
|
||||||
import { getNewBoardState, makeMove, passTurn, updateCaptures, updateChains } from "../boardState/boardState";
|
import { getNewBoardState, makeMove, passTurn, updateCaptures, updateChains } from "../boardState/boardState";
|
||||||
import { makeAIMove } from "../boardAnalysis/goAI";
|
import { makeAIMove, resetAI } from "../boardAnalysis/goAI";
|
||||||
import {
|
import {
|
||||||
evaluateIfMoveIsValid,
|
evaluateIfMoveIsValid,
|
||||||
getControlledSpace,
|
getControlledSpace,
|
||||||
@ -292,6 +292,7 @@ export function resetBoardState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Go.currentGame = getNewBoardState(boardSize, opponent, true);
|
Go.currentGame = getNewBoardState(boardSize, opponent, true);
|
||||||
|
resetAI(false);
|
||||||
GoEvents.emit(); // Trigger a Go UI rerender
|
GoEvents.emit(); // Trigger a Go UI rerender
|
||||||
logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`);
|
logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`);
|
||||||
return simpleBoardFromBoard(Go.currentGame.board);
|
return simpleBoardFromBoard(Go.currentGame.board);
|
||||||
|
@ -18,7 +18,7 @@ import { GoScoreModal } from "./GoScoreModal";
|
|||||||
import { GoGameboard } from "./GoGameboard";
|
import { GoGameboard } from "./GoGameboard";
|
||||||
import { GoSubnetSearch } from "./GoSubnetSearch";
|
import { GoSubnetSearch } from "./GoSubnetSearch";
|
||||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||||
import { makeAIMove, resolveCurrentTurn } from "../boardAnalysis/goAI";
|
import { makeAIMove, resetAI, resolveCurrentTurn } from "../boardAnalysis/goAI";
|
||||||
import { GoScoreExplanation } from "./GoScoreExplanation";
|
import { GoScoreExplanation } from "./GoScoreExplanation";
|
||||||
|
|
||||||
interface GoGameboardWrapperProps {
|
interface GoGameboardWrapperProps {
|
||||||
@ -144,6 +144,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
|||||||
}
|
}
|
||||||
|
|
||||||
Go.currentGame = getNewBoardState(newBoardSize, newOpponent, true);
|
Go.currentGame = getNewBoardState(newBoardSize, newOpponent, true);
|
||||||
|
resetAI(false);
|
||||||
rerender();
|
rerender();
|
||||||
resolveCurrentTurn();
|
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.
|
* 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",
|
* 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