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
This commit is contained in:
Michael Ficocelli 2024-03-28 01:02:53 -04:00 committed by GitHub
parent 8553bcb8fc
commit fe87f1f628
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 34 additions and 14 deletions

@ -9,9 +9,9 @@ Returns the name of the opponent faction in the current subnet.
**Signature:** **Signature:**
```typescript ```typescript
getOpponent(): GoOpponent | "No AI" | "????????????"; getOpponent(): GoOpponent | "No AI";
``` ```
**Returns:** **Returns:**
[GoOpponent](./bitburner.goopponent.md) \| "No AI" \| "????????????" [GoOpponent](./bitburner.goopponent.md) \| "No AI"

@ -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. | | [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. | | [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 "Daedalus" or "Illuminati",</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 "????????????",</p> |

@ -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. 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:** **Signature:**

@ -8,5 +8,5 @@
**Signature:** **Signature:**
```typescript ```typescript
type GoOpponent = "Netburners" | "Slum Snakes" | "The Black Hand" | "Tetrads" | "Daedalus" | "Illuminati"; type GoOpponent = "Netburners" | "Slum Snakes" | "The Black Hand" | "Tetrads" | "Daedalus" | "Illuminati" | "????????????";
``` ```

@ -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 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).
&nbsp; &nbsp;
#### Overview #### Overview

@ -336,7 +336,12 @@ function logEndGame(logger: (s: string) => void) {
/** /**
* Clears the board, resets winstreak if applicable * 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) { 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`); error(`Invalid subnet size requested (${boardSize}), size must be 5, 7, 9, or 13`);
return; return;
@ -354,6 +359,7 @@ export function resetBoardState(error: (s: string) => void, opponent: GoOpponent
Go.currentGame = getNewBoardState(boardSize, opponent, true); Go.currentGame = getNewBoardState(boardSize, opponent, true);
GoEvents.emit(); // Trigger a Go UI rerender GoEvents.emit(); // Trigger a Go UI rerender
logger(`New game started: ${opponent}, ${boardSize}x${boardSize}`);
return simpleBoardFromBoard(Go.currentGame.board); 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 // 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) { else if (state.cheatCount && (ejectRngOverride ?? rng.random()) < 0.1) {
logger(`Cheat failed! You have been ejected from the subnet.`); 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 { return {
type: GoPlayType.gameOver, type: GoPlayType.gameOver,
x: null, x: null,

@ -68,7 +68,7 @@ export function NetscriptGo(): InternalAPI<NSGo> {
const opponent = getEnumHelper("GoOpponent").nsGetMember(ctx, _opponent); const opponent = getEnumHelper("GoOpponent").nsGetMember(ctx, _opponent);
const boardSize = helpers.number(ctx, "boardSize", _boardSize); const boardSize = helpers.number(ctx, "boardSize", _boardSize);
return resetBoardState(error(ctx), opponent, boardSize); return resetBoardState(logger(ctx), error(ctx), opponent, boardSize);
}, },
analysis: { analysis: {
getValidMoves: () => () => { getValidMoves: () => () => {

@ -3926,7 +3926,14 @@ export interface Gang {
} }
/** @public */ /** @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 * IPvGO api
@ -4035,7 +4042,7 @@ export interface Go {
/** /**
* Returns the name of the opponent faction in the current subnet. * 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. * 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. * 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 * @returns a simplified version of the board state as an array of strings representing the board columns. See ns.Go.getBoardState() for full details
* *

@ -99,20 +99,24 @@ describe("Netscript Go API unit tests", () => {
it("should set the player's board to the requested size and opponent", () => { it("should set the player's board to the requested size and opponent", () => {
const board = ["OXX..", ".....", ".....", ".....", "..###"]; const board = ["OXX..", ".....", ".....", ".....", "..###"];
Go.currentGame = boardStateFromSimpleBoard(board); Go.currentGame = boardStateFromSimpleBoard(board);
const mockLogger = jest.fn();
const mockError = 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(newBoard?.[0].length).toEqual(9);
expect(Go.currentGame.board.length).toEqual(9); expect(Go.currentGame.board.length).toEqual(9);
expect(Go.currentGame.ai).toEqual(GoOpponent.SlumSnakes); 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", () => { it("should throw an error if an invalid opponent is requested", () => {
const board = ["OXX..", ".....", ".....", ".....", "..###"]; const board = ["OXX..", ".....", ".....", ".....", "..###"];
Go.currentGame = boardStateFromSimpleBoard(board); Go.currentGame = boardStateFromSimpleBoard(board);
const mockLogger = jest.fn();
const mockError = jest.fn(); const mockError = jest.fn();
resetBoardState(mockError, GoOpponent.w0r1d_d43m0n, 9); resetBoardState(mockLogger, mockError, GoOpponent.w0r1d_d43m0n, 9);
expect(mockError).toHaveBeenCalledWith( expect(mockError).toHaveBeenCalledWith(
`Invalid opponent requested (${GoOpponent.w0r1d_d43m0n}), this opponent has not yet been discovered`, `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", () => { it("should throw an error if an invalid size is requested", () => {
const board = ["OXX..", ".....", ".....", ".....", "..###"]; const board = ["OXX..", ".....", ".....", ".....", "..###"];
Go.currentGame = boardStateFromSimpleBoard(board); Go.currentGame = boardStateFromSimpleBoard(board);
const mockLogger = jest.fn();
const mockError = 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"); expect(mockError).toHaveBeenCalledWith("Invalid subnet size requested (31337), size must be 5, 7, 9, or 13");
}); });