From fe87f1f628e6d433596cc271166a59cfd85f93b2 Mon Sep 17 00:00:00 2001 From: Michael Ficocelli Date: Thu, 28 Mar 2024 01:02:53 -0400 Subject: [PATCH] IPVGO: Bugfixes (#1193) * IPVGO: Explicitly link the generated API documentation in the algorithm design doc * IPVGO: Fix missing factions in netscript docs * IPVGO: Linting * IPVGO: Ensure resetBoardState() logs that a new game has started --- markdown/bitburner.go.getopponent.md | 4 ++-- markdown/bitburner.go.md | 2 +- markdown/bitburner.go.resetboardstate.md | 2 +- markdown/bitburner.goopponent.md | 2 +- src/Documentation/doc/programming/go_algorithms.md | 2 ++ src/Go/effects/netscriptGoImplementation.ts | 10 ++++++++-- src/NetscriptFunctions/Go.ts | 2 +- src/ScriptEditor/NetscriptDefinitions.d.ts | 13 ++++++++++--- test/jest/Go/NetscriptGo.test.ts | 11 ++++++++--- 9 files changed, 34 insertions(+), 14 deletions(-) diff --git a/markdown/bitburner.go.getopponent.md b/markdown/bitburner.go.getopponent.md index 8a2e09f77..0d60bbce6 100644 --- a/markdown/bitburner.go.getopponent.md +++ b/markdown/bitburner.go.getopponent.md @@ -9,9 +9,9 @@ Returns the name of the opponent faction in the current subnet. **Signature:** ```typescript -getOpponent(): GoOpponent | "No AI" | "????????????"; +getOpponent(): GoOpponent | "No AI"; ``` **Returns:** -[GoOpponent](./bitburner.goopponent.md) \| "No AI" \| "????????????" +[GoOpponent](./bitburner.goopponent.md) \| "No AI" diff --git a/markdown/bitburner.go.md b/markdown/bitburner.go.md index f1c0106e5..a42497d2d 100644 --- a/markdown/bitburner.go.md +++ b/markdown/bitburner.go.md @@ -30,5 +30,5 @@ export interface Go | [makeMove(x, y)](./bitburner.go.makemove.md) | Make a move on the IPvGO subnet gameboard, 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) |

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.

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.

| -| [resetBoardState(opponent, boardSize)](./bitburner.go.resetboardstate.md) |

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.

opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Daedalus" or "Illuminati",

| +| [resetBoardState(opponent, boardSize)](./bitburner.go.resetboardstate.md) |

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.

opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????",

| diff --git a/markdown/bitburner.go.resetboardstate.md b/markdown/bitburner.go.resetboardstate.md index 6f0226dab..afec085ef 100644 --- a/markdown/bitburner.go.resetboardstate.md +++ b/markdown/bitburner.go.resetboardstate.md @@ -8,7 +8,7 @@ Gets new IPvGO subnet with the specified size owned by the listed faction, ready Note that some factions will have a few routers on the subnet at this state. -opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Daedalus" or "Illuminati", +opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????", **Signature:** diff --git a/markdown/bitburner.goopponent.md b/markdown/bitburner.goopponent.md index 3fa33b73e..6a63f3f1f 100644 --- a/markdown/bitburner.goopponent.md +++ b/markdown/bitburner.goopponent.md @@ -8,5 +8,5 @@ **Signature:** ```typescript -type GoOpponent = "Netburners" | "Slum Snakes" | "The Black Hand" | "Tetrads" | "Daedalus" | "Illuminati"; +type GoOpponent = "Netburners" | "Slum Snakes" | "The Black Hand" | "Tetrads" | "Daedalus" | "Illuminati" | "????????????"; ``` diff --git a/src/Documentation/doc/programming/go_algorithms.md b/src/Documentation/doc/programming/go_algorithms.md index 8d7e75d4a..56347c960 100644 --- a/src/Documentation/doc/programming/go_algorithms.md +++ b/src/Documentation/doc/programming/go_algorithms.md @@ -4,6 +4,8 @@ IPvGO is a strategic territory control minigame accessible from DefComm in New T For basic instructions, go to DefComm or CIA to access the current subnet, and look through the "How to Play" section. This document is specifically focused on building scripts to automate subnet takeover, which will be more applicable you have played a few subnets. +For a full list of all IpvGO methods and their descriptions and documentation, you can use the game's [API documentation page](https://github.com/bitburner-official/bitburner-src/blob/dev/markdown/bitburner.go.md). +   #### Overview diff --git a/src/Go/effects/netscriptGoImplementation.ts b/src/Go/effects/netscriptGoImplementation.ts index 40d1012c1..ac6094fb1 100644 --- a/src/Go/effects/netscriptGoImplementation.ts +++ b/src/Go/effects/netscriptGoImplementation.ts @@ -336,7 +336,12 @@ function logEndGame(logger: (s: string) => void) { /** * Clears the board, resets winstreak if applicable */ -export function resetBoardState(error: (s: string) => void, opponent: GoOpponent, boardSize: number) { +export function resetBoardState( + logger: (s: string) => void, + error: (s: string) => void, + opponent: GoOpponent, + boardSize: number, +) { if (![5, 7, 9, 13].includes(boardSize) && opponent !== GoOpponent.w0r1d_d43m0n) { error(`Invalid subnet size requested (${boardSize}), size must be 5, 7, 9, or 13`); return; @@ -354,6 +359,7 @@ export function resetBoardState(error: (s: string) => void, opponent: GoOpponent Go.currentGame = getNewBoardState(boardSize, opponent, true); GoEvents.emit(); // Trigger a Go UI rerender + logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`); return simpleBoardFromBoard(Go.currentGame.board); } @@ -392,7 +398,7 @@ export async function determineCheatSuccess( // If there have been prior cheat attempts, and the cheat fails, there is a 10% chance of instantly losing else if (state.cheatCount && (ejectRngOverride ?? rng.random()) < 0.1) { logger(`Cheat failed! You have been ejected from the subnet.`); - resetBoardState(logger, state.ai, state.board[0].length); + resetBoardState(logger, logger, state.ai, state.board[0].length); return { type: GoPlayType.gameOver, x: null, diff --git a/src/NetscriptFunctions/Go.ts b/src/NetscriptFunctions/Go.ts index 46bfd82a6..12c98e033 100644 --- a/src/NetscriptFunctions/Go.ts +++ b/src/NetscriptFunctions/Go.ts @@ -68,7 +68,7 @@ export function NetscriptGo(): InternalAPI { const opponent = getEnumHelper("GoOpponent").nsGetMember(ctx, _opponent); const boardSize = helpers.number(ctx, "boardSize", _boardSize); - return resetBoardState(error(ctx), opponent, boardSize); + return resetBoardState(logger(ctx), error(ctx), opponent, boardSize); }, analysis: { getValidMoves: () => () => { diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index a54d21244..72ae88bad 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -3926,7 +3926,14 @@ export interface Gang { } /** @public */ -type GoOpponent = "Netburners" | "Slum Snakes" | "The Black Hand" | "Tetrads" | "Daedalus" | "Illuminati"; +type GoOpponent = + | "Netburners" + | "Slum Snakes" + | "The Black Hand" + | "Tetrads" + | "Daedalus" + | "Illuminati" + | "????????????"; /** * IPvGO api @@ -4035,7 +4042,7 @@ export interface Go { /** * Returns the name of the opponent faction in the current subnet. */ - getOpponent(): GoOpponent | "No AI" | "????????????"; + getOpponent(): GoOpponent | "No AI"; /** * Gets new IPvGO subnet with the specified size owned by the listed faction, ready for the player to make a move. @@ -4044,7 +4051,7 @@ export interface Go { * * Note that some factions will have a few routers on the subnet at this state. * - * opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Daedalus" or "Illuminati", + * opponent is "Netburners" or "Slum Snakes" or "The Black Hand" or "Tetrads" or "Daedalus" or "Illuminati" or "????????????", * * @returns a simplified version of the board state as an array of strings representing the board columns. See ns.Go.getBoardState() for full details * diff --git a/test/jest/Go/NetscriptGo.test.ts b/test/jest/Go/NetscriptGo.test.ts index b477aea46..f771031ce 100644 --- a/test/jest/Go/NetscriptGo.test.ts +++ b/test/jest/Go/NetscriptGo.test.ts @@ -99,20 +99,24 @@ describe("Netscript Go API unit tests", () => { it("should set the player's board to the requested size and opponent", () => { const board = ["OXX..", ".....", ".....", ".....", "..###"]; Go.currentGame = boardStateFromSimpleBoard(board); + const mockLogger = jest.fn(); const mockError = jest.fn(); - const newBoard = resetBoardState(mockError, GoOpponent.SlumSnakes, 9); + const newBoard = resetBoardState(mockLogger, mockError, GoOpponent.SlumSnakes, 9); expect(newBoard?.[0].length).toEqual(9); expect(Go.currentGame.board.length).toEqual(9); expect(Go.currentGame.ai).toEqual(GoOpponent.SlumSnakes); + expect(mockError).not.toHaveBeenCalled(); + expect(mockLogger).toHaveBeenCalledWith(`New game started: ${GoOpponent.SlumSnakes}, 9x9`); }); it("should throw an error if an invalid opponent is requested", () => { const board = ["OXX..", ".....", ".....", ".....", "..###"]; Go.currentGame = boardStateFromSimpleBoard(board); + const mockLogger = jest.fn(); const mockError = jest.fn(); - resetBoardState(mockError, GoOpponent.w0r1d_d43m0n, 9); + resetBoardState(mockLogger, mockError, GoOpponent.w0r1d_d43m0n, 9); expect(mockError).toHaveBeenCalledWith( `Invalid opponent requested (${GoOpponent.w0r1d_d43m0n}), this opponent has not yet been discovered`, @@ -121,9 +125,10 @@ describe("Netscript Go API unit tests", () => { it("should throw an error if an invalid size is requested", () => { const board = ["OXX..", ".....", ".....", ".....", "..###"]; Go.currentGame = boardStateFromSimpleBoard(board); + const mockLogger = jest.fn(); const mockError = jest.fn(); - resetBoardState(mockError, GoOpponent.TheBlackHand, 31337); + resetBoardState(mockLogger, mockError, GoOpponent.TheBlackHand, 31337); expect(mockError).toHaveBeenCalledWith("Invalid subnet size requested (31337), size must be 5, 7, 9, or 13"); });