mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-08 08:43:53 +01:00
IPVGO: Balance and improvements for offline bonus time cycles (#1356)
This commit is contained in:
parent
463d4cdb1d
commit
481938a2fb
@ -28,7 +28,7 @@ let currentTurnResolver: (() => void) | null = null;
|
||||
/**
|
||||
* Retrieves a move from the current faction in response to the player's move
|
||||
*/
|
||||
export function makeAIMove(boardState: BoardState): Promise<Play> {
|
||||
export function makeAIMove(boardState: BoardState, useOfflineCycles = true): Promise<Play> {
|
||||
// If AI is already taking their turn, return the existing turn.
|
||||
if (isAiThinking) {
|
||||
return Go.nextTurn;
|
||||
@ -43,31 +43,33 @@ export function makeAIMove(boardState: BoardState): Promise<Play> {
|
||||
}
|
||||
// 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 {
|
||||
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai).then(async (play): Promise<Play> => {
|
||||
if (boardState !== Go.currentGame) return play; //Stale game
|
||||
Go.nextTurn = getMove(boardState, GoColor.white, Go.currentGame.ai, useOfflineCycles).then(
|
||||
async (play): Promise<Play> => {
|
||||
if (boardState !== Go.currentGame) return play; //Stale game
|
||||
|
||||
// Handle AI passing
|
||||
if (play.type === GoPlayType.pass) {
|
||||
passTurn(boardState, GoColor.white);
|
||||
// if passTurn called endGoGame, or the player has no valid moves left, the move should be shown as a game over
|
||||
if (boardState.previousPlayer === null || !getAllValidMoves(boardState, GoColor.black).length) {
|
||||
return { type: GoPlayType.gameOver, x: null, y: null };
|
||||
// Handle AI passing
|
||||
if (play.type === GoPlayType.pass) {
|
||||
passTurn(boardState, GoColor.white);
|
||||
// if passTurn called endGoGame, or the player has no valid moves left, the move should be shown as a game over
|
||||
if (boardState.previousPlayer === null || !getAllValidMoves(boardState, GoColor.black).length) {
|
||||
return { type: GoPlayType.gameOver, x: null, y: null };
|
||||
}
|
||||
return play;
|
||||
}
|
||||
|
||||
// Handle AI making a move
|
||||
await waitCycle(useOfflineCycles);
|
||||
const aiUpdatedBoard = makeMove(boardState, play.x, play.y, GoColor.white);
|
||||
|
||||
// Handle the AI breaking. This shouldn't ever happen.
|
||||
if (!aiUpdatedBoard) {
|
||||
boardState.previousPlayer = GoColor.white;
|
||||
console.error(`Invalid AI move attempted: ${play.x}, ${play.y}. This should not happen.`);
|
||||
}
|
||||
|
||||
return play;
|
||||
}
|
||||
|
||||
// Handle AI making a move
|
||||
await waitCycle();
|
||||
const aiUpdatedBoard = makeMove(boardState, play.x, play.y, GoColor.white);
|
||||
|
||||
// Handle the AI breaking. This shouldn't ever happen.
|
||||
if (!aiUpdatedBoard) {
|
||||
boardState.previousPlayer = GoColor.white;
|
||||
console.error(`Invalid AI move attempted: ${play.x}, ${play.y}. This should not happen.`);
|
||||
}
|
||||
|
||||
return play;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Once the AI moves (or the player playing as white with No AI moves),
|
||||
@ -112,9 +114,10 @@ export async function getMove(
|
||||
boardState: BoardState,
|
||||
player: GoColor,
|
||||
opponent: GoOpponent,
|
||||
useOfflineCycles = true,
|
||||
rngOverride?: number,
|
||||
): Promise<Play & { type: GoPlayType.move | GoPlayType.pass }> {
|
||||
await waitCycle();
|
||||
await waitCycle(useOfflineCycles);
|
||||
const rng = new WHRNG(rngOverride || Player.totalPlaytime);
|
||||
const smart = isSmart(opponent, rng.random());
|
||||
const moves = getMoveOptions(boardState, player, rng.random(), smart);
|
||||
@ -142,7 +145,7 @@ export async function getMove(
|
||||
.filter((point) => evaluateIfMoveIsValid(boardState, point.x, point.y, player, false));
|
||||
|
||||
const chosenMove = moveOptions[Math.floor(rng.random() * moveOptions.length)];
|
||||
await waitCycle();
|
||||
await waitCycle(useOfflineCycles);
|
||||
|
||||
if (chosenMove) {
|
||||
//console.debug(`Non-priority move chosen: ${chosenMove.x} ${chosenMove.y}`);
|
||||
@ -817,9 +820,9 @@ export function sleep(ms: number): Promise<void> {
|
||||
* Spend some time waiting to allow the UI & CSS to render smoothly
|
||||
* If bonus time is available, significantly decrease the length of the wait
|
||||
*/
|
||||
function waitCycle(): Promise<void> {
|
||||
if (Go.storedCycles > 0) {
|
||||
Go.storedCycles -= 1;
|
||||
function waitCycle(useOfflineCycles = true): Promise<void> {
|
||||
if (useOfflineCycles && Go.storedCycles > 0) {
|
||||
Go.storedCycles -= 2;
|
||||
return sleep(40);
|
||||
}
|
||||
return sleep(200);
|
||||
|
@ -115,7 +115,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
||||
return;
|
||||
}
|
||||
|
||||
const move = await makeAIMove(boardState);
|
||||
const move = await makeAIMove(boardState, false);
|
||||
|
||||
if (move.type === GoPlayType.pass) {
|
||||
SnackbarEvents.emit(`The opponent passes their turn; It is now your turn to move.`, ToastVariant.WARNING, 4000);
|
||||
|
@ -31,7 +31,7 @@ describe("Go AI tests", () => {
|
||||
it("prioritizes eye creation moves for Illuminati", async () => {
|
||||
const board = ["...O...", "OOOO...", ".......", ".......", ".......", ".......", "......."];
|
||||
const boardState = boardStateFromSimpleBoard(board, GoOpponent.Daedalus);
|
||||
const move = await getMove(boardState, GoColor.white, GoOpponent.Daedalus, 0);
|
||||
const move = await getMove(boardState, GoColor.white, GoOpponent.Daedalus, false, 0);
|
||||
|
||||
expect([move.x, move.y]).toEqual([0, 1]);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user