mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-22 14:12:27 +01:00
283 lines
12 KiB
TypeScript
283 lines
12 KiB
TypeScript
|
import { getBoardFromSimplifiedBoardState, getSimplifiedBoardState } from "../../../src/Go/boardAnalysis/boardAnalysis";
|
||
|
import {
|
||
|
cheatPlayTwoMoves,
|
||
|
cheatRemoveRouter,
|
||
|
cheatRepairOfflineNode,
|
||
|
getChains,
|
||
|
getControlledEmptyNodes,
|
||
|
getLiberties,
|
||
|
getValidMoves,
|
||
|
handlePassTurn,
|
||
|
invalidMoveResponse,
|
||
|
makePlayerMove,
|
||
|
resetBoardState,
|
||
|
} from "../../../src/Go/effects/netscriptGoImplementation";
|
||
|
import { Player, setPlayer } from "@player";
|
||
|
import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
|
||
|
import "../../../src/Faction/Factions";
|
||
|
import { opponents, playerColors, playTypes } from "../../../src/Go/boardState/goConstants";
|
||
|
import { getNewBoardState } from "../../../src/Go/boardState/boardState";
|
||
|
|
||
|
jest.mock("../../../src/Faction/Factions", () => ({
|
||
|
Factions: {},
|
||
|
}));
|
||
|
|
||
|
setPlayer(new PlayerObject());
|
||
|
|
||
|
describe("Netscript Go API unit tests", () => {
|
||
|
describe("makeMove() tests", () => {
|
||
|
it("should handle invalid moves", async () => {
|
||
|
const board = ["XOO..", ".....", ".....", ".....", "....."];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await makePlayerMove(mockLogger, 0, 0);
|
||
|
|
||
|
expect(result).toEqual(invalidMoveResponse);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("ERROR: Invalid move: That node is already occupied by a piece");
|
||
|
});
|
||
|
|
||
|
it("should update the board with valid player moves", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....."];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await makePlayerMove(mockLogger, 1, 0);
|
||
|
|
||
|
expect(result.success).toEqual(true);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Go move played: 1, 0");
|
||
|
expect(Player.go.boardState.board[1]?.[0]?.player).toEqual(playerColors.black);
|
||
|
expect(Player.go.boardState.board[0]?.[0]?.player).toEqual(playerColors.empty);
|
||
|
});
|
||
|
});
|
||
|
describe("passTurn() tests", () => {
|
||
|
it("should handle pass attempts", async () => {
|
||
|
Player.go.boardState = getNewBoardState(7);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await handlePassTurn(mockLogger);
|
||
|
|
||
|
expect(result.success).toEqual(true);
|
||
|
expect(result.type).toEqual(playTypes.move);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("getBoardState() tests", () => {
|
||
|
it("should correctly return a string version of the bard state", () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "..###"];
|
||
|
const boardState = getBoardFromSimplifiedBoardState(board);
|
||
|
|
||
|
const result = getSimplifiedBoardState(boardState.board);
|
||
|
|
||
|
expect(result).toEqual(board);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("resetBoardState() tests", () => {
|
||
|
it("should set the player's board to the requested size and opponent", () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "..###"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board);
|
||
|
const mockError = jest.fn();
|
||
|
|
||
|
const newBoard = resetBoardState(mockError, opponents.SlumSnakes, 9);
|
||
|
|
||
|
expect(newBoard?.[0].length).toEqual(9);
|
||
|
expect(Player.go.boardState.board.length).toEqual(9);
|
||
|
expect(Player.go.boardState.ai).toEqual(opponents.SlumSnakes);
|
||
|
});
|
||
|
it("should throw an error if an invalid opponent is requested", () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "..###"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board);
|
||
|
const mockError = jest.fn();
|
||
|
|
||
|
resetBoardState(mockError, "fake opponent", 9);
|
||
|
|
||
|
expect(mockError).toHaveBeenCalledWith(
|
||
|
"Invalid opponent requested (fake opponent), valid options are Netburners, Slum Snakes, The Black Hand, Tetrads, Daedalus, Illuminati",
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it("should throw an error if an invalid size is requested", () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "..###"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board);
|
||
|
const mockError = jest.fn();
|
||
|
|
||
|
resetBoardState(mockError, opponents.TheBlackHand, 31337);
|
||
|
|
||
|
expect(mockError).toHaveBeenCalledWith("Invalid subnet size requested (31337, size must be 5, 7, 9, or 13");
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("getValidMoves() unit tests", () => {
|
||
|
it("should return all valid and invalid moves on the board", () => {
|
||
|
const board = ["XXO.#", "XO.O.", ".OOOO", "XXXXX", "X.X.X"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
|
||
|
const result = getValidMoves();
|
||
|
|
||
|
expect(result).toEqual([
|
||
|
[false, false, false, false, false],
|
||
|
[false, false, false, false, false],
|
||
|
[true, false, false, false, false],
|
||
|
[false, false, false, false, false],
|
||
|
[false, true, false, true, false],
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("getChains() unit tests", () => {
|
||
|
it("should assign an ID to all contiguous chains on the board", () => {
|
||
|
const board = ["XXO.#", "XO.O.", ".OOOO", "XXXXX", "X.X.X"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
|
||
|
const result = getChains();
|
||
|
|
||
|
expect(result[4][0]).toEqual(result[3][4]);
|
||
|
expect(result[2][1]).toEqual(result[1][3]);
|
||
|
expect(result[0][0]).toEqual(result[1][0]);
|
||
|
expect(result[0][4]).toEqual(null);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("getLiberties() unit tests", () => {
|
||
|
it("should display the number of connected empty nodes for each chain on the board", () => {
|
||
|
const board = ["XXO.#", "XO.O.", ".OOOO", "XXXXX", "X.X.X"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
|
||
|
const result = getLiberties();
|
||
|
|
||
|
expect(result).toEqual([
|
||
|
[1, 1, 2, -1, -1],
|
||
|
[1, 4, -1, 4, -1],
|
||
|
[-1, 4, 4, 4, 4],
|
||
|
[3, 3, 3, 3, 3],
|
||
|
[3, -1, 3, -1, 3],
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
describe("getControlledEmptyNodes() unit tests", () => {
|
||
|
it("should show the owner of each empty node, if a single player has fully encircled it", () => {
|
||
|
const board = ["XXO.#", "XO.O.", ".OOOO", "XXXXX", "X.X.X"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
|
||
|
const result = getControlledEmptyNodes();
|
||
|
|
||
|
expect(result).toEqual(["...O#", "..O.O", "?....", ".....", ".X.X."]);
|
||
|
});
|
||
|
});
|
||
|
describe("cheatPlayTwoMoves() tests", () => {
|
||
|
it("should handle invalid moves", async () => {
|
||
|
const board = ["XOO..", ".....", ".....", ".....", "....."];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatPlayTwoMoves(mockLogger, 0, 0, 1, 0, 0, 0);
|
||
|
|
||
|
expect(result).toEqual(invalidMoveResponse);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("The point 0,0 is not empty, so you cannot place a router there.");
|
||
|
});
|
||
|
|
||
|
it("should update the board with both player moves if nodes are unoccupied and cheat is successful", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....O"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatPlayTwoMoves(mockLogger, 4, 3, 3, 4, 0, 0);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat successful. Two go moves played: 4,3 and 3,4");
|
||
|
expect(result.success).toEqual(true);
|
||
|
expect(Player.go.boardState.board[4]?.[3]?.player).toEqual(playerColors.black);
|
||
|
expect(Player.go.boardState.board[3]?.[4]?.player).toEqual(playerColors.black);
|
||
|
expect(Player.go.boardState.board[4]?.[4]?.player).toEqual(playerColors.empty);
|
||
|
});
|
||
|
|
||
|
it("should pass player turn to AI if the cheat is unsuccessful but player is not ejected", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....O"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatPlayTwoMoves(mockLogger, 4, 3, 3, 4, 2, 1);
|
||
|
console.log(result);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat failed. Your turn has been skipped.");
|
||
|
expect(result.success).toEqual(false);
|
||
|
expect(Player.go.boardState.board[4]?.[3]?.player).toEqual(playerColors.empty);
|
||
|
expect(Player.go.boardState.board[3]?.[4]?.player).toEqual(playerColors.empty);
|
||
|
expect(Player.go.boardState.board[4]?.[4]?.player).toEqual(playerColors.white);
|
||
|
});
|
||
|
|
||
|
it("should reset the board if the cheat is unsuccessful and the player is ejected", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....O"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
Player.go.boardState.cheatCount = 1;
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatPlayTwoMoves(mockLogger, 4, 3, 3, 4, 1, 0);
|
||
|
console.log(result);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat failed! You have been ejected from the subnet.");
|
||
|
expect(result.success).toEqual(false);
|
||
|
expect(Player.go.boardState.history.length).toEqual(0);
|
||
|
});
|
||
|
});
|
||
|
describe("cheatRemoveRouter() tests", () => {
|
||
|
it("should handle invalid moves", async () => {
|
||
|
const board = ["XOO..", ".....", ".....", ".....", "....."];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatRemoveRouter(mockLogger, 1, 0, 0, 0);
|
||
|
|
||
|
expect(result).toEqual(invalidMoveResponse);
|
||
|
expect(mockLogger).toHaveBeenCalledWith(
|
||
|
"The point 1,0 does not have a router on it, so you cannot clear this point with removeRouter().",
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it("should remove the router if the move is valid", async () => {
|
||
|
const board = ["XOO..", ".....", ".....", ".....", "....."];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatRemoveRouter(mockLogger, 0, 0, 0, 0);
|
||
|
|
||
|
expect(result.success).toEqual(true);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat successful. The point 0,0 was cleared.");
|
||
|
expect(Player.go.boardState.board[0][0]?.player).toEqual(playerColors.empty);
|
||
|
});
|
||
|
|
||
|
it("should reset the board if the cheat is unsuccessful and the player is ejected", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....O"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
Player.go.boardState.cheatCount = 1;
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatRemoveRouter(mockLogger, 0, 0, 1, 0);
|
||
|
console.log(result);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat failed! You have been ejected from the subnet.");
|
||
|
expect(result.success).toEqual(false);
|
||
|
expect(Player.go.boardState.history.length).toEqual(0);
|
||
|
});
|
||
|
});
|
||
|
describe("cheatRepairOfflineNode() tests", () => {
|
||
|
it("should handle invalid moves", async () => {
|
||
|
const board = ["XOO..", ".....", ".....", ".....", "....#"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatRepairOfflineNode(mockLogger, 0, 0);
|
||
|
|
||
|
expect(result).toEqual(invalidMoveResponse);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("The node 0,0 is not offline, so you cannot repair the node.");
|
||
|
});
|
||
|
|
||
|
it("should update the board with the repaired node if the cheat is successful", async () => {
|
||
|
const board = ["OXX..", ".....", ".....", ".....", "....#"];
|
||
|
Player.go.boardState = getBoardFromSimplifiedBoardState(board, opponents.Daedalus, playerColors.white);
|
||
|
const mockLogger = jest.fn();
|
||
|
|
||
|
const result = await cheatRepairOfflineNode(mockLogger, 4, 4, 0, 0);
|
||
|
expect(mockLogger).toHaveBeenCalledWith("Cheat successful. The point 4,4 was repaired.");
|
||
|
expect(result.success).toEqual(true);
|
||
|
expect(Player.go.boardState.board[4]?.[4]?.player).toEqual(playerColors.empty);
|
||
|
});
|
||
|
});
|
||
|
});
|