CODEBASE: Fix lint errors 4 (#1773)

Co-authored-by: Michael Ficocelli <ficocemt@gmail.com>
This commit is contained in:
catloversg 2024-11-14 22:47:35 +07:00 committed by GitHub
parent 4f84a894eb
commit 97ca8c5f5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 123 additions and 99 deletions

@ -85,7 +85,7 @@ export function loadGo(data: unknown): boolean {
// If it's the AI's turn, initiate their turn, which will populate nextTurn
if (currentGame.previousPlayer === GoColor.black && currentGame.ai !== GoOpponent.none) {
makeAIMove(currentGame).catch((error) => {
showError(error);
showError(new Error(`Error while making first IPvGO AI move: ${error}`, { cause: error }));
});
}
// If it's not the AI's turn and we're not in gameover status, initialize nextTurn promise based on the previous move/pass
@ -152,9 +152,10 @@ function loadStats(stats: unknown): PartialRecord<GoOpponent, OpponentStats> | s
const entries = Object.entries(stats);
for (const [opponent, opponentStats] of entries) {
if (!getEnumHelper("GoOpponent").isMember(opponent)) return `Invalid opponent in Go.stats: ${opponent}`;
if (!opponentStats || typeof opponentStats !== "object") "Non-object encountered for an opponent's stats";
assertLoadingType<OpponentStats>(opponentStats);
const { favor, highestWinStreak, losses, nodes, wins, oldWinStreak, winStreak, nodePower } = opponentStats;
if (!opponentStats || typeof opponentStats !== "object") return "Non-object encountered for an opponent's stats";
assertLoadingType<OpponentStats>(opponentStats as object);
const { favor, highestWinStreak, losses, nodes, wins, oldWinStreak, winStreak, nodePower } =
opponentStats as OpponentStats;
// Integers >= 0. Todo: make a better helper for this.
if (!isInteger(favor) || favor < 0) return "A favor entry in Go.stats was invalid";
if (!isInteger(highestWinStreak) || highestWinStreak < 0) return "A highestWinStreak entry in Go.stats was invalid";
@ -183,7 +184,7 @@ function loadSimpleBoard(simpleBoard: unknown, requiredSize?: number): SimpleBoa
if (!simpleBoard.every((column) => typeof column === "string" && column.length === requiredSize)) {
return "Incorrect types or column size while loading a SimpleBoard.";
}
return simpleBoard;
return simpleBoard as SimpleBoard;
}
function loadStoredCycles(storedCycles: unknown): number {

@ -11,7 +11,7 @@ export type Move = {
createsLife?: boolean;
};
type MoveType =
export type MoveType =
| "capture"
| "defendCapture"
| "eyeMove"
@ -25,8 +25,20 @@ type MoveType =
| "corner"
| "random";
type MoveFunction = () => Promise<Move | null>;
export type MoveOptions = Record<MoveType, MoveFunction>;
export type MoveOptions = {
readonly eyeMove: () => Move | null;
readonly random: () => Move | null;
readonly defendCapture: () => Promise<Move | null>;
readonly corner: () => Move | null;
readonly defend: () => Move | null;
readonly pattern: () => Promise<Move | null>;
readonly capture: () => Promise<Move | null>;
readonly growth: () => Move | null;
readonly eyeBlock: () => Move | null;
readonly surround: () => Move | null;
readonly expansion: () => Move | null;
readonly jump: () => Move | null;
};
export type EyeMove = {
point: PointState;

@ -696,16 +696,14 @@ export function getPreviousMove(): [number, number] | null {
return null;
}
for (const rowIndexString in Go.currentGame.board) {
const row = Go.currentGame.board[+rowIndexString] ?? [];
for (const pointIndexString in row) {
const point = row[+pointIndexString];
const priorColor = point && priorBoard && getColorOnBoardString(priorBoard, point.x, point.y);
for (const [rowIndex, row] of Go.currentGame.board.entries()) {
for (const [pointIndex, point] of row.entries()) {
const priorColor = point && getColorOnBoardString(priorBoard, point.x, point.y);
const currentColor = point?.color;
const isPreviousPlayer = currentColor === Go.currentGame.previousPlayer;
const isChanged = priorColor !== currentColor;
if (priorColor && currentColor && isPreviousPlayer && isChanged) {
return [+rowIndexString, +pointIndexString];
return [rowIndex, pointIndex];
}
}
}

@ -1,4 +1,4 @@
import type { Board, BoardState, EyeMove, Move, MoveOptions, Play, PointState } from "../Types";
import type { Board, BoardState, EyeMove, Move, MoveOptions, MoveType, Play, PointState } from "../Types";
import { Player } from "@player";
import { AugmentationName, GoColor, GoOpponent, GoPlayType } from "@enums";
@ -153,13 +153,13 @@ export async function getMove(
// If no priority move is chosen, pick one of the reasonable moves
const moveOptions = [
(await moves.growth())?.point,
(await moves.surround())?.point,
(await moves.defend())?.point,
(await moves.expansion())?.point,
moves.growth()?.point,
moves.surround()?.point,
moves.defend()?.point,
moves.expansion()?.point,
(await moves.pattern())?.point,
(await moves.eyeMove())?.point,
(await moves.eyeBlock())?.point,
moves.eyeMove()?.point,
moves.eyeBlock()?.point,
]
.filter(isNotNullish)
.filter((point) => evaluateIfMoveIsValid(boardState, point.x, point.y, player, false));
@ -221,12 +221,12 @@ function isSmart(faction: GoOpponent, rng: number) {
async function getNetburnersPriorityMove(moves: MoveOptions, rng: number): Promise<PointState | null> {
if (rng < 0.2) {
return getIlluminatiPriorityMove(moves, rng);
} else if (rng < 0.4 && (await moves.expansion())) {
return (await moves.expansion())?.point ?? null;
} else if (rng < 0.6 && (await moves.growth())) {
return (await moves.growth())?.point ?? null;
} else if (rng < 0.4 && moves.expansion()) {
return moves.expansion()?.point ?? null;
} else if (rng < 0.6 && moves.growth()) {
return moves.growth()?.point ?? null;
} else if (rng < 0.75) {
return (await moves.random())?.point ?? null;
return moves.random()?.point ?? null;
}
return null;
@ -242,10 +242,10 @@ async function getSlumSnakesPriorityMove(moves: MoveOptions, rng: number): Promi
if (rng < 0.2) {
return getIlluminatiPriorityMove(moves, rng);
} else if (rng < 0.6 && (await moves.growth())) {
return (await moves.growth())?.point ?? null;
} else if (rng < 0.6 && moves.growth()) {
return moves.growth()?.point ?? null;
} else if (rng < 0.65) {
return (await moves.random())?.point ?? null;
return moves.random()?.point ?? null;
}
return null;
@ -260,7 +260,7 @@ async function getBlackHandPriorityMove(moves: MoveOptions, rng: number): Promis
return (await moves.capture())?.point ?? null;
}
const surround = await moves.surround();
const surround = moves.surround();
if (surround && surround.point && (surround.newLibertyCount ?? 999) <= 1) {
//console.debug("surround move chosen");
@ -282,7 +282,7 @@ async function getBlackHandPriorityMove(moves: MoveOptions, rng: number): Promis
} else if (rng < 0.75 && surround) {
return surround.point;
} else if (rng < 0.8) {
return (await moves.random())?.point ?? null;
return moves.random()?.point ?? null;
}
return null;
@ -307,7 +307,7 @@ async function getTetradPriorityMove(moves: MoveOptions, rng: number): Promise<P
return (await moves.pattern())?.point ?? null;
}
const surround = await moves.surround();
const surround = moves.surround();
if (surround && surround.point && (surround?.newLibertyCount ?? 9) <= 1) {
//console.debug("surround move chosen");
return surround.point;
@ -350,30 +350,28 @@ async function getIlluminatiPriorityMove(moves: MoveOptions, rng: number): Promi
return (await moves.defendCapture())?.point ?? null;
}
if (await moves.eyeMove()) {
if (moves.eyeMove()) {
//console.debug("Create eye move chosen");
return (await moves.eyeMove())?.point ?? null;
return moves.eyeMove()?.point ?? null;
}
const surround = await moves.surround();
const surround = moves.surround();
if (surround && surround.point && (surround?.newLibertyCount ?? 9) <= 1) {
//console.debug("surround move chosen");
return surround.point;
}
if (await moves.eyeBlock()) {
if (moves.eyeBlock()) {
//console.debug("Block eye move chosen");
return (await moves.eyeBlock())?.point ?? null;
return moves.eyeBlock()?.point ?? null;
}
if (await moves.corner()) {
if (moves.corner()) {
//console.debug("Corner move chosen");
return (await moves.corner())?.point ?? null;
return moves.corner()?.point ?? null;
}
const hasMoves = [await moves.eyeMove(), await moves.eyeBlock(), await moves.growth(), moves.defend, surround].filter(
(m) => m,
).length;
const hasMoves = [moves.eyeMove(), moves.eyeBlock(), moves.growth(), moves.defend, surround].filter((m) => m).length;
const usePattern = rng > 0.25 || !hasMoves;
if ((await moves.pattern()) && usePattern) {
@ -381,9 +379,9 @@ async function getIlluminatiPriorityMove(moves: MoveOptions, rng: number): Promi
return (await moves.pattern())?.point ?? null;
}
if (rng > 0.4 && (await moves.jump())) {
if (rng > 0.4 && moves.jump()) {
//console.debug("Jump move chosen");
return (await moves.jump())?.point ?? null;
return moves.jump()?.point ?? null;
}
if (rng < 0.6 && surround && surround.point && (surround?.newLibertyCount ?? 9) <= 2) {
@ -508,7 +506,7 @@ function getDisputedTerritoryMoves(board: Board, availableSpaces: PointState[],
/**
* Finds all moves that increases the liberties of the player's pieces, making them harder to capture and occupy more space on the board.
*/
async function getLibertyGrowthMoves(board: Board, player: GoColor, availableSpaces: PointState[]) {
function getLibertyGrowthMoves(board: Board, player: GoColor, availableSpaces: PointState[]) {
const friendlyChains = getAllChains(board).filter((chain) => chain[0].color === player);
if (!friendlyChains.length) {
@ -551,8 +549,8 @@ async function getLibertyGrowthMoves(board: Board, player: GoColor, availableSpa
/**
* Find a move that increases the player's liberties by the maximum amount
*/
async function getGrowthMove(board: Board, player: GoColor, availableSpaces: PointState[], rng: number) {
const growthMoves = await getLibertyGrowthMoves(board, player, availableSpaces);
function getGrowthMove(board: Board, player: GoColor, availableSpaces: PointState[], rng: number) {
const growthMoves = getLibertyGrowthMoves(board, player, availableSpaces);
const maxLibertyCount = Math.max(...growthMoves.map((l) => l.newLibertyCount - l.oldLibertyCount));
@ -563,8 +561,8 @@ async function getGrowthMove(board: Board, player: GoColor, availableSpaces: Poi
/**
* Find a move that specifically increases a chain's liberties from 1 to more than 1, preventing capture
*/
async function getDefendMove(board: Board, player: GoColor, availableSpaces: PointState[]) {
const growthMoves = await getLibertyGrowthMoves(board, player, availableSpaces);
function getDefendMove(board: Board, player: GoColor, availableSpaces: PointState[]) {
const growthMoves = getLibertyGrowthMoves(board, player, availableSpaces);
const libertyIncreases =
growthMoves?.filter((move) => move.oldLibertyCount <= 1 && move.newLibertyCount > move.oldLibertyCount) ?? [];
@ -582,7 +580,7 @@ async function getDefendMove(board: Board, player: GoColor, availableSpaces: Poi
* Find a move that reduces the opponent's liberties as much as possible,
* capturing (or making it easier to capture) their pieces
*/
async function getSurroundMove(board: Board, player: GoColor, availableSpaces: PointState[], smart = true) {
function getSurroundMove(board: Board, player: GoColor, availableSpaces: PointState[], smart = true) {
const opposingPlayer = player === GoColor.black ? GoColor.white : GoColor.black;
const enemyChains = getAllChains(board).filter((chain) => chain[0].color === opposingPlayer);
@ -741,12 +739,7 @@ function getEyeBlockingMove(board: Board, player: GoColor, availablePoints: Poin
/**
* Gets a group of reasonable moves based on the current board state, to be passed to the factions' AI to decide on
*/
function getMoveOptions(
boardState: BoardState,
player: GoColor,
rng: number,
smart = true,
): { [s in keyof MoveOptions]: () => Promise<Move | null> } {
function getMoveOptions(boardState: BoardState, player: GoColor, rng: number, smart = true) {
const board = boardState.board;
const availableSpaces = findDisputedTerritory(boardState, player, smart);
const contestedPoints = getDisputedTerritoryMoves(board, availableSpaces);
@ -756,7 +749,7 @@ function getMoveOptions(
// needlessly extend the game, unless they actually can change the score
const endGameAvailable = !contestedPoints.length && boardState.passCount;
const moveOptions: { [s in keyof MoveOptions]: Move | null | undefined } = {
const moveOptions: { [s in MoveType]: Move | null | undefined } = {
capture: undefined,
defendCapture: undefined,
eyeMove: undefined,
@ -771,7 +764,7 @@ function getMoveOptions(
random: undefined,
};
const moveOptionGetters: { [s in keyof MoveOptions]: () => Promise<Move | null> } = {
const moveOptionGetters: MoveOptions = {
capture: async () => {
const surroundMove = await retrieveMoveOption("surround");
return surroundMove && surroundMove?.newLibertyCount === 0 ? surroundMove : null;
@ -785,30 +778,30 @@ function getMoveOptions(
? defendMove
: null;
},
eyeMove: async () => (endGameAvailable ? null : getEyeCreationMove(board, player, availableSpaces) ?? null),
eyeBlock: async () => (endGameAvailable ? null : getEyeBlockingMove(board, player, availableSpaces) ?? null),
eyeMove: () => (endGameAvailable ? null : getEyeCreationMove(board, player, availableSpaces) ?? null),
eyeBlock: () => (endGameAvailable ? null : getEyeBlockingMove(board, player, availableSpaces) ?? null),
pattern: async () => {
const point = endGameAvailable ? null : await findAnyMatchedPatterns(board, player, availableSpaces, smart, rng);
return point ? { point } : null;
},
growth: async () => (endGameAvailable ? null : (await getGrowthMove(board, player, availableSpaces, rng)) ?? null),
expansion: async () => (await getExpansionMove(board, availableSpaces, rng, expansionMoves)) ?? null,
jump: async () => (await getJumpMove(board, player, availableSpaces, rng, expansionMoves)) ?? null,
defend: async () => (await getDefendMove(board, player, availableSpaces)) ?? null,
surround: async () => (await getSurroundMove(board, player, availableSpaces, smart)) ?? null,
corner: async () => {
growth: () => (endGameAvailable ? null : getGrowthMove(board, player, availableSpaces, rng) ?? null),
expansion: () => getExpansionMove(board, availableSpaces, rng, expansionMoves) ?? null,
jump: () => getJumpMove(board, player, availableSpaces, rng, expansionMoves) ?? null,
defend: () => getDefendMove(board, player, availableSpaces) ?? null,
surround: () => getSurroundMove(board, player, availableSpaces, smart) ?? null,
corner: () => {
const point = getCornerMove(board);
return point ? { point } : null;
},
random: async () => {
random: () => {
// Only offer a random move if there are some contested spaces on the board.
// (Random move should not be picked if the AI would otherwise pass turn.)
const point = contestedPoints.length ? availableSpaces[Math.floor(rng * availableSpaces.length)] : null;
return point ? { point } : null;
},
};
} as const;
async function retrieveMoveOption(id: keyof typeof moveOptions): Promise<Move | null> {
async function retrieveMoveOption(id: MoveType): Promise<Move | null> {
await waitCycle();
if (moveOptions[id] !== undefined) {
return moveOptions[id] ?? null;

@ -2,8 +2,8 @@
import type { Board, PointState } from "../Types";
import { GoColor } from "@enums";
import { sleep } from "./goAI";
import { findEffectiveLibertiesOfNewMove } from "./boardAnalysis";
import { sleep } from "./goAI";
export const threeByThreePatterns = [
// 3x3 piece patterns; X,O are color pieces; x,o are any state except the opposite color piece;

@ -24,7 +24,7 @@ const fadeLoop = keyframes`
}
`;
export const pointStyle = makeStyles<void, Size | Point | Structure | Highlight>({ uniqId: "pointStyle" })(
export const pointStyle = makeStyles<unknown, Size | Point | Structure | Highlight>({ uniqId: "pointStyle" })(
(theme: Theme, _, classes) => ({
hover: {},
valid: {},
@ -396,7 +396,7 @@ export const pointStyle = makeStyles<void, Size | Point | Structure | Highlight>
}),
);
export const boardStyles = makeStyles<void, Size | "background">({ uniqId: "boardStyles" })(
export const boardStyles = makeStyles<unknown, Size | "background">({ uniqId: "boardStyles" })(
(theme: Theme, _, classes) => ({
tab: {
paddingTop: 0,

@ -472,7 +472,11 @@ export function cheatRemoveRouter(
successRngOverride?: number,
ejectRngOverride?: number,
): Promise<Play> {
const point = Go.currentGame.board[x][y]!;
const point = Go.currentGame.board[x][y];
if (!point) {
logger(`Cheat failed. The point ${x},${y} is already offline.`);
return Go.nextTurn;
}
return determineCheatSuccess(
logger,
() => {
@ -498,8 +502,13 @@ export function cheatPlayTwoMoves(
successRngOverride?: number,
ejectRngOverride?: number,
): Promise<Play> {
const point1 = Go.currentGame.board[x1][y1]!;
const point2 = Go.currentGame.board[x2][y2]!;
const point1 = Go.currentGame.board[x1][y1];
const point2 = Go.currentGame.board[x2][y2];
if (!point1 || !point2) {
logger(`Cheat failed. One of the points ${x1},${y1} or ${x2},${y2} is already offline.`);
return Go.nextTurn;
}
return determineCheatSuccess(
logger,

@ -11,7 +11,7 @@ import { getAllValidMoves, getControlledSpace } from "../boardAnalysis/boardAnal
interface GoGameboardProps {
boardState: BoardState;
traditional: boolean;
clickHandler: (x: number, y: number) => any;
clickHandler: (x: number, y: number) => unknown;
hover: boolean;
}
@ -27,7 +27,7 @@ export function GoGameboard({ boardState, traditional, clickHandler, hover }: Go
}
const boardSize = boardState.board[0].length;
const { classes } = boardStyles();
const { classes } = boardStyles({});
return (
<Grid container id="goGameboard" className={`${classes.board} ${traditional ? classes.traditional : ""}`}>

@ -49,7 +49,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
const [scoreExplanationOpen, setScoreExplanationOpen] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
const { classes } = boardStyles();
const { classes } = boardStyles({});
const boardSize = boardState.board[0].length;
const currentPlayer = boardState.previousPlayer === GoColor.white ? GoColor.black : GoColor.white;
const waitingOnAI = boardState.previousPlayer === GoColor.black && boardState.ai !== GoOpponent.none;

@ -16,7 +16,7 @@ import { getRecordKeys } from "../../Types/Record";
export const GoHistoryPage = (): React.ReactElement => {
useRerender(400);
const { classes } = boardStyles();
const { classes } = boardStyles({});
const priorBoard = Go.previousGame ?? getNewBoardState(7);
const score = getScore(priorBoard);
const opponent = priorBoard.ai;

@ -70,7 +70,7 @@ const makeTwoEyesChallenge = (
);
export const GoInstructionsPage = (): React.ReactElement => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
return (
<div className={classes.instructionScroller}>
<>

@ -19,7 +19,7 @@ interface GoPointProps {
}
export function GoPoint({ state, x, y, traditional, hover, valid, emptyPointOwner }: GoPointProps): React.ReactElement {
const { classes } = pointStyle();
const { classes } = pointStyle({});
const currentPoint = state.board[x]?.[y];
const player = currentPoint?.color;

@ -9,7 +9,7 @@ import { GoGameboardWrapper } from "./GoGameboardWrapper";
import { boardStyles } from "../boardState/goStyles";
export function GoRoot(): React.ReactElement {
const { classes } = boardStyles();
const { classes } = boardStyles({});
const [value, setValue] = React.useState(0);
function handleChange(event: React.SyntheticEvent, tab: number): void {

@ -10,7 +10,7 @@ interface Props {
}
export const GoScoreExplanation = ({ open, onClose }: Props): React.ReactElement => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
return (
<Modal open={open} onClose={onClose}>

@ -25,7 +25,7 @@ export const GoScoreModal = ({
showScoreExplanation,
opponent,
}: Props): React.ReactElement => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
const blackScore = finalScore[GoColor.black];
const whiteScore = finalScore[GoColor.white];

@ -18,7 +18,7 @@ interface Props {
}
export const GoScorePowerSummary = ({ finalScore, opponent }: Props) => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
const status = getOpponentStats(opponent);
const winStreak = status.winStreak;
const oldWinStreak = status.winStreak;

@ -12,7 +12,7 @@ interface GoScoreSummaryTableProps {
}
export const GoScoreSummaryTable = ({ score, opponent }: GoScoreSummaryTableProps) => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
const blackScore = score[GoColor.black];
const whiteScore = score[GoColor.white];
const blackPlayerName = opponent === GoOpponent.none ? GoColor.black : "You";

@ -13,7 +13,7 @@ import { GoOpponent } from "@enums";
export const GoStatusPage = (): React.ReactElement => {
useRerender(400);
const { classes } = boardStyles();
const { classes } = boardStyles({});
const score = getScore(Go.currentGame);
const opponent = Go.currentGame.ai;
const playedOpponentList = getRecordKeys(Go.stats).filter((o) => o !== GoOpponent.none);

@ -21,7 +21,7 @@ interface IProps {
const boardSizeOptions = boardSizes.filter((size) => size !== 19);
export const GoSubnetSearch = ({ open, search, cancel, showInstructions }: IProps): React.ReactElement => {
const { classes } = boardStyles();
const { classes } = boardStyles({});
const [opponent, setOpponent] = useState<GoOpponent>(Go.currentGame?.ai ?? GoOpponent.SlumSnakes);
const preselectedBoardSize =
opponent === GoOpponent.w0r1d_d43m0n ? 19 : Math.min(Go.currentGame?.board?.[0]?.length ?? 7, 13);

@ -33,7 +33,7 @@ export function GoTutorialChallenge({
incorrectText2,
}: IProps): React.ReactElement {
const stateRef = useRef(getStateCopy(state));
const { classes } = boardStyles();
const { classes } = boardStyles({});
const [displayText, setDisplayText] = useState(description);
const [showReset, setShowReset] = useState(false);

@ -53,7 +53,7 @@ describe("Netscript Go API unit tests", () => {
throw new Error("Invalid");
});
await makePlayerMove(mockLogger, mockError, 0, 0).catch((_) => _);
await makePlayerMove(mockLogger, mockError, 0, 0).catch(() => {});
expect(mockError).toHaveBeenCalledWith("Invalid move: 0 0. That node is already occupied by a piece.");
});
@ -95,7 +95,7 @@ describe("Netscript Go API unit tests", () => {
});
describe("getGameState() tests", () => {
it("should correctly retrieve the current game state", async () => {
it("should correctly retrieve the current game state", () => {
const board = ["OXX..", ".....", "..#..", "...XX", "...X."];
const boardState = boardStateFromSimpleBoard(board, GoOpponent.Daedalus, GoColor.black);
boardState.previousBoards = ["OX.........#.....XX...X."];
@ -240,7 +240,7 @@ describe("Netscript Go API unit tests", () => {
});
});
describe("cheatPlayTwoMoves() tests", () => {
it("should handle invalid moves", async () => {
it("should handle invalid moves", () => {
const board = ["XOO..", ".....", ".....", ".....", "....."];
Go.currentGame = boardStateFromSimpleBoard(board, GoOpponent.Daedalus, GoColor.white);
const mockError = jest.fn();
@ -289,7 +289,7 @@ describe("Netscript Go API unit tests", () => {
});
});
describe("cheatRemoveRouter() tests", () => {
it("should handle invalid moves", async () => {
it("should handle invalid moves", () => {
const board = ["XOO..", ".....", ".....", ".....", "....."];
Go.currentGame = boardStateFromSimpleBoard(board, GoOpponent.Daedalus, GoColor.white);
const mockError = jest.fn();
@ -327,7 +327,7 @@ describe("Netscript Go API unit tests", () => {
});
});
describe("cheatRepairOfflineNode() tests", () => {
it("should handle invalid moves", async () => {
it("should handle invalid moves", () => {
const board = ["XOO..", ".....", ".....", ".....", "....#"];
Go.currentGame = boardStateFromSimpleBoard(board, GoOpponent.Daedalus, GoColor.white);
const mockError = jest.fn();

@ -6,13 +6,15 @@ import {
getAllValidMoves,
boardStateFromSimpleBoard,
evaluateIfMoveIsValid,
getPreviousMove,
} from "../../../src/Go/boardAnalysis/boardAnalysis";
import { findAnyMatchedPatterns } from "../../../src/Go/boardAnalysis/patternMatching";
import { Go } from "../../../src/Go/Go";
setPlayer(new PlayerObject());
describe("Go board analysis tests", () => {
it("identifies chains and liberties", async () => {
it("identifies chains and liberties", () => {
const board = ["XOO..", ".....", ".....", ".....", "....."];
const boardState = boardStateFromSimpleBoard(board);
@ -20,7 +22,7 @@ describe("Go board analysis tests", () => {
expect(boardState.board[0]?.[1]?.liberties?.length).toEqual(3);
});
it("identifies all points that are part of 'eyes' on the board", async () => {
it("identifies all points that are part of 'eyes' on the board", () => {
const board = ["..O..", "OOOOO", "..XXX", "..XX.", "..X.X"];
const boardState = boardStateFromSimpleBoard(board);
@ -46,7 +48,7 @@ describe("Go board analysis tests", () => {
expect(point?.y).toEqual(2);
});
it("identifies invalid moves from self-capture", async () => {
it("identifies invalid moves from self-capture", () => {
const board = [".X...", "X....", ".....", ".....", "....."];
const boardState = boardStateFromSimpleBoard(board);
const validity = evaluateIfMoveIsValid(boardState, 0, 0, GoColor.white, false);
@ -54,7 +56,7 @@ describe("Go board analysis tests", () => {
expect(validity).toEqual(GoValidity.noSuicide);
});
it("identifies invalid moves from repeat", async () => {
it("identifies invalid moves from repeat", () => {
const board = [".X...", ".....", ".....", ".....", "....."];
const boardState = boardStateFromSimpleBoard(board);
boardState.previousBoards.push(".X.......................");
@ -65,4 +67,12 @@ describe("Go board analysis tests", () => {
expect(validity).toEqual(GoValidity.boardRepeated);
});
it("identifies the previous move made, based on the board history", () => {
const board = [".XXO.", ".....", ".....", ".....", "....."];
Go.currentGame = boardStateFromSimpleBoard(board);
Go.currentGame.previousBoards.push("..XO.....................");
expect(getPreviousMove()).toEqual([0, 1]);
});
});

@ -13,13 +13,14 @@ describe("Board analysis utility tests", () => {
.filter((p) => p === "O").length;
expect(whitePieceCount).toEqual(1);
expect(result).toEqual({
board: expect.any(Object),
board: result.board, // This board state is different every run, due to random offline nodes and handicap placement
previousPlayer: GoColor.white,
previousBoards: [],
ai: GoOpponent.Illuminati,
passCount: 0,
cheatCount: 0,
});
expect(result.board?.length).toEqual(5);
});
it("Correctly applies the board size and handicap for the special opponent", () => {