From 38d99ff15ec2e5d6e28108a2e8983304c56afb45 Mon Sep 17 00:00:00 2001 From: David Walker Date: Thu, 16 May 2024 12:26:18 -0700 Subject: [PATCH] IPVGO: Remove unneeded functions from boardState.ts (#1270) --- src/Go/boardAnalysis/boardAnalysis.ts | 20 ++++------- src/Go/boardAnalysis/controlledTerritory.ts | 4 +-- src/Go/boardAnalysis/goAI.ts | 26 +++++++------- src/Go/boardAnalysis/patternMatching.ts | 3 +- src/Go/boardAnalysis/scoring.ts | 6 ++-- src/Go/boardState/boardState.ts | 38 ++++++--------------- src/Go/boardState/offlineNodes.ts | 7 ++-- 7 files changed, 38 insertions(+), 66 deletions(-) diff --git a/src/Go/boardAnalysis/boardAnalysis.ts b/src/Go/boardAnalysis/boardAnalysis.ts index deb6d9824..9a3fee8b1 100644 --- a/src/Go/boardAnalysis/boardAnalysis.ts +++ b/src/Go/boardAnalysis/boardAnalysis.ts @@ -9,8 +9,7 @@ import { getBoardCopy, getEmptySpaces, getNewBoardState, - isDefined, - isNotNull, + isNotNullish, updateCaptures, updateChains, } from "../boardState/boardState"; @@ -155,9 +154,7 @@ const resetChainsById = (board: Board, chainIds: string[]) => { export function findEffectiveLibertiesOfNewMove(board: Board, x: number, y: number, player: GoColor) { const friendlyChains = getAllChains(board).filter((chain) => chain[0].color === player); const neighbors = findAdjacentLibertiesAndAlliesForPoint(board, x, y, player); - const neighborPoints = [neighbors.north, neighbors.east, neighbors.south, neighbors.west] - .filter(isNotNull) - .filter(isDefined); + const neighborPoints = [neighbors.north, neighbors.east, neighbors.south, neighbors.west].filter(isNotNullish); // Get all chains that the new move will connect to const allyNeighbors = neighborPoints.filter((neighbor) => neighbor.color === player); const allyNeighborChainLiberties = allyNeighbors @@ -166,7 +163,7 @@ export function findEffectiveLibertiesOfNewMove(board: Board, x: number, y: numb return chain?.[0]?.liberties ?? null; }) .flat() - .filter(isNotNull); + .filter(isNotNullish); // Get all empty spaces that the new move connects to that aren't already part of friendly liberties const directLiberties = neighborPoints.filter((neighbor) => neighbor.color === GoColor.empty); @@ -188,8 +185,7 @@ export function findEffectiveLibertiesOfNewMove(board: Board, x: number, y: numb export function findMaxLibertyCountOfAdjacentChains(boardState: BoardState, x: number, y: number, player: GoColor) { const neighbors = findAdjacentLibertiesAndAlliesForPoint(boardState.board, x, y, player); const friendlyNeighbors = [neighbors.north, neighbors.east, neighbors.south, neighbors.west] - .filter(isNotNull) - .filter(isDefined) + .filter(isNotNullish) .filter((neighbor) => neighbor.color === player); return friendlyNeighbors.reduce((max, neighbor) => Math.max(max, neighbor?.liberties?.length ?? 0), 0); @@ -207,8 +203,7 @@ export function findEnemyNeighborChainWithFewestLiberties(board: Board, x: numbe const chains = getAllChains(board); const neighbors = findAdjacentLibertiesAndAlliesForPoint(board, x, y, player); const friendlyNeighbors = [neighbors.north, neighbors.east, neighbors.south, neighbors.west] - .filter(isNotNull) - .filter(isDefined) + .filter(isNotNullish) .filter((neighbor) => neighbor.color === player); const minimumLiberties = friendlyNeighbors.reduce( @@ -353,10 +348,7 @@ function findNeighboringChainsThatFullyEncircleEmptySpace( const evaluationBoard = getBoardCopy(board); const examplePoint = candidateChain[0]; - const otherChainNeighborPoints = removePointAtIndex(neighborChainList, index) - .flat() - .filter(isNotNull) - .filter(isDefined); + const otherChainNeighborPoints = removePointAtIndex(neighborChainList, index).flat().filter(isNotNullish); otherChainNeighborPoints.forEach((point) => { const pointToEdit = evaluationBoard[point.x]?.[point.y]; if (pointToEdit) { diff --git a/src/Go/boardAnalysis/controlledTerritory.ts b/src/Go/boardAnalysis/controlledTerritory.ts index 91f7bfdc6..71911aef5 100644 --- a/src/Go/boardAnalysis/controlledTerritory.ts +++ b/src/Go/boardAnalysis/controlledTerritory.ts @@ -8,7 +8,7 @@ import { getAllPotentialEyes, getAllValidMoves, } from "./boardAnalysis"; -import { contains, isNotNull } from "../boardState/boardState"; +import { contains, isNotNullish } from "../boardState/boardState"; /** * Any empty space fully encircled by the opponent is not worth playing in, unless one of its borders explicitly has a weakness @@ -57,7 +57,7 @@ export function findDisputedTerritory(boardState: BoardState, player: GoColor, e } const libertiesInsideOfSpaceToAnalyze = liberties - .filter(isNotNull) + .filter(isNotNullish) .filter((point) => contains(space.chain, point)); // If the chain has any liberties outside the empty space being analyzed, it is not yet fully surrounded, diff --git a/src/Go/boardAnalysis/goAI.ts b/src/Go/boardAnalysis/goAI.ts index 33709a5cf..885ab716d 100644 --- a/src/Go/boardAnalysis/goAI.ts +++ b/src/Go/boardAnalysis/goAI.ts @@ -3,7 +3,7 @@ import type { Board, BoardState, EyeMove, Move, MoveOptions, Play, PointState } import { Player } from "@player"; import { AugmentationName, GoOpponent, GoColor, GoPlayType } from "@enums"; import { opponentDetails } from "../Constants"; -import { findNeighbors, floor, isDefined, isNotNull, makeMove, passTurn } from "../boardState/boardState"; +import { findNeighbors, isNotNullish, makeMove, passTurn } from "../boardState/boardState"; import { evaluateIfMoveIsValid, evaluateMoveResult, @@ -111,11 +111,10 @@ export async function getMove( (await moves.eyeMove())?.point, (await moves.eyeBlock())?.point, ] - .filter(isNotNull) - .filter(isDefined) + .filter(isNotNullish) .filter((point) => evaluateIfMoveIsValid(boardState, point.x, point.y, player, false)); - const chosenMove = moveOptions[floor(rng.random() * moveOptions.length)]; + const chosenMove = moveOptions[Math.floor(rng.random() * moveOptions.length)]; if (chosenMove) { await sleep(200); @@ -393,7 +392,7 @@ function isCornerAvailableForMove(board: Board, x1: number, y1: number, x2: numb */ function getExpansionMove(board: Board, availableSpaces: PointState[], rng: number, moveArray?: Move[]) { const moveOptions = moveArray ?? getExpansionMoveArray(board, availableSpaces); - const randomIndex = floor(rng * moveOptions.length); + const randomIndex = Math.floor(rng * moveOptions.length); return moveOptions[randomIndex]; } @@ -410,7 +409,7 @@ function getJumpMove(board: Board, player: GoColor, availableSpaces: PointState[ ].some((point) => point?.color === player), ); - const randomIndex = floor(rng * moveOptions.length); + const randomIndex = Math.floor(rng * moveOptions.length); return moveOptions[randomIndex]; } @@ -469,14 +468,13 @@ async function getLibertyGrowthMoves(board: Board, player: GoColor, availableSpa // Get all liberties of friendly chains as potential growth move options const liberties = friendlyChains .map((chain) => - chain[0].liberties?.filter(isNotNull).map((liberty) => ({ + chain[0].liberties?.filter(isNotNullish).map((liberty) => ({ libertyPoint: liberty, oldLibertyCount: chain[0].liberties?.length, })), ) .flat() - .filter(isNotNull) - .filter(isDefined) + .filter(isNotNullish) .filter((liberty) => availableSpaces.find((point) => liberty.libertyPoint.x === point.x && liberty.libertyPoint.y === point.y), ); @@ -509,7 +507,7 @@ async function getGrowthMove(board: Board, player: GoColor, availableSpaces: Poi const maxLibertyCount = Math.max(...growthMoves.map((l) => l.newLibertyCount - l.oldLibertyCount)); const moveCandidates = growthMoves.filter((l) => l.newLibertyCount - l.oldLibertyCount === maxLibertyCount); - return moveCandidates[floor(rng * moveCandidates.length)]; + return moveCandidates[Math.floor(rng * moveCandidates.length)]; } /** @@ -527,7 +525,7 @@ async function getDefendMove(board: Board, player: GoColor, availableSpaces: Poi } const moveCandidates = libertyIncreases.filter((l) => l.newLibertyCount - l.oldLibertyCount === maxLibertyCount); - return moveCandidates[floor(Math.random() * moveCandidates.length)]; + return moveCandidates[Math.floor(Math.random() * moveCandidates.length)]; } /** @@ -546,7 +544,7 @@ async function getSurroundMove(board: Board, player: GoColor, availableSpaces: P .map((chain) => chain[0].liberties) .flat() .filter((liberty) => availableSpaces.find((point) => liberty?.x === point.x && liberty?.y === point.y)) - .filter(isNotNull); + .filter(isNotNullish); const captureMoves: Move[] = []; const atariMoves: Move[] = []; @@ -635,7 +633,7 @@ function getEyeCreationMoves(board: Board, player: GoColor, availableSpaces: Poi .filter((chain) => !currentLivingGroupIDs.includes(chain[0].chain)) .map((chain) => chain[0].liberties) .flat() - .filter(isNotNull) + .filter(isNotNullish) .filter((point) => availableSpaces.find((availablePoint) => availablePoint.x === point.x && availablePoint.y === point.y), ) @@ -755,7 +753,7 @@ function getMoveOptions( random: async () => { // 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[floor(rng * availableSpaces.length)] : null; + const point = contestedPoints.length ? availableSpaces[Math.floor(rng * availableSpaces.length)] : null; return point ? { point } : null; }, }; diff --git a/src/Go/boardAnalysis/patternMatching.ts b/src/Go/boardAnalysis/patternMatching.ts index 4d53d414e..6ed25f2bc 100644 --- a/src/Go/boardAnalysis/patternMatching.ts +++ b/src/Go/boardAnalysis/patternMatching.ts @@ -4,7 +4,6 @@ import type { Board, PointState } from "../Types"; import { GoColor } from "@enums"; import { sleep } from "./goAI"; import { findEffectiveLibertiesOfNewMove } from "./boardAnalysis"; -import { floor } from "../boardState/boardState"; export const threeByThreePatterns = [ // 3x3 piece patterns; X,O are color pieces; x,o are any state except the opposite color piece; @@ -104,7 +103,7 @@ export async function findAnyMatchedPatterns( } await sleep(10); } - return moves[floor(rng * moves.length)] || null; + return moves[Math.floor(rng * moves.length)] || null; } /** diff --git a/src/Go/boardAnalysis/scoring.ts b/src/Go/boardAnalysis/scoring.ts index 3591bd223..196998a6c 100644 --- a/src/Go/boardAnalysis/scoring.ts +++ b/src/Go/boardAnalysis/scoring.ts @@ -6,7 +6,7 @@ import { newOpponentStats } from "../Constants"; import { getAllChains, getPlayerNeighbors } from "./boardAnalysis"; import { getKomi } from "./goAI"; import { getDifficultyMultiplier, getMaxFavor, getWinstreakMultiplier } from "../effects/effect"; -import { floor, isNotNull } from "../boardState/boardState"; +import { isNotNullish } from "../boardState/boardState"; import { Factions } from "../../Faction/Factions"; import { getEnumHelper } from "../../utils/EnumHelper"; import { Go } from "../Go"; @@ -59,7 +59,7 @@ export function endGoGame(boardState: BoardState) { if (score[GoColor.black].sum < score[GoColor.white].sum) { resetWinstreak(boardState.ai, true); - statusToUpdate.nodePower += floor(score[GoColor.black].sum * 0.25); + statusToUpdate.nodePower += Math.floor(score[GoColor.black].sum * 0.25); } else { statusToUpdate.wins++; statusToUpdate.oldWinStreak = statusToUpdate.winStreak; @@ -114,7 +114,7 @@ export function resetWinstreak(opponent: GoOpponent, gameComplete: boolean) { */ function getColoredPieceCount(boardState: BoardState, color: GoColor) { return boardState.board.reduce( - (sum, row) => sum + row.filter(isNotNull).filter((point) => point.color === color).length, + (sum, row) => sum + row.filter(isNotNullish).filter((point) => point.color === color).length, 0, ); } diff --git a/src/Go/boardState/boardState.ts b/src/Go/boardState/boardState.ts index 4ef9a66e4..3eb80e841 100644 --- a/src/Go/boardState/boardState.ts +++ b/src/Go/boardState/boardState.ts @@ -140,7 +140,7 @@ export function applyHandicap(board: Board, handicap: number): void { // select random distinct moves from the move options list up to the specified handicap amount for (let i = 0; i < handicap && i < handicapMoveOptions.length; i++) { - const index = floor(Math.random() * handicapMoveOptions.length); + const index = Math.floor(Math.random() * handicapMoveOptions.length); handicapMoves.push(handicapMoveOptions[index]); handicapMoveOptions.splice(index, 1); } @@ -247,16 +247,13 @@ export function findAdjacentPointsInChain(board: Board, x: number, y: number) { checkedPoints.push(currentPoint); const neighbors = findNeighbors(board, currentPoint.x, currentPoint.y); - [neighbors.north, neighbors.east, neighbors.south, neighbors.west] - .filter(isNotNull) - .filter(isDefined) - .forEach((neighbor) => { - if (neighbor && neighbor.color === currentPoint.color && !contains(checkedPoints, neighbor)) { - adjacentPoints.push(neighbor); - pointsToCheckNeighbors.push(neighbor); - } - checkedPoints.push(neighbor); - }); + [neighbors.north, neighbors.east, neighbors.south, neighbors.west].filter(isNotNullish).forEach((neighbor) => { + if (neighbor && neighbor.color === currentPoint.color && !contains(checkedPoints, neighbor)) { + adjacentPoints.push(neighbor); + pointsToCheckNeighbors.push(neighbor); + } + checkedPoints.push(neighbor); + }); } return adjacentPoints; @@ -312,22 +309,9 @@ export function findNeighbors(board: Board, x: number, y: number): Neighbor { } export function getArrayFromNeighbor(neighborObject: Neighbor): PointState[] { - return [neighborObject.north, neighborObject.east, neighborObject.south, neighborObject.west] - .filter(isNotNull) - .filter(isDefined); + return [neighborObject.north, neighborObject.east, neighborObject.south, neighborObject.west].filter(isNotNullish); } -export function isNotNull(argument: T | null): argument is T { - return argument !== null; -} -export function isDefined(argument: T | undefined): argument is T { - return argument !== undefined; -} - -export function floor(n: number) { - return ~~n; -} -export function ceil(n: number) { - const floored = floor(n); - return floored === n ? n : floored + 1; +export function isNotNullish(argument: T | undefined | null): argument is T { + return argument != null; } diff --git a/src/Go/boardState/offlineNodes.ts b/src/Go/boardState/offlineNodes.ts index 519593600..5044a5217 100644 --- a/src/Go/boardState/offlineNodes.ts +++ b/src/Go/boardState/offlineNodes.ts @@ -3,13 +3,12 @@ import type { Board, BoardState, PointState } from "../Types"; import { Player } from "@player"; import { boardSizes } from "../Constants"; import { WHRNG } from "../../Casino/RNG"; -import { floor } from "./boardState"; type rand = (n1: number, n2: number) => number; export function addObstacles(boardState: BoardState) { const rng = new WHRNG(Player.totalPlaytime ?? new Date().getTime()); - const random = (n1: number, n2: number) => n1 + floor((n2 - n1 + 1) * rng.random()); + const random = (n1: number, n2: number) => n1 + Math.floor((n2 - n1 + 1) * rng.random()); const shouldRemoveCorner = !random(0, 4); const shouldRemoveRows = !shouldRemoveCorner && !random(0, 4); @@ -105,8 +104,8 @@ function addDeadCorner(board: Board, random: rand, size: number) { function addCenterBreak(board: Board, random: rand) { const size = board[0].length; const maxOffset = getScale(board); - const xIndex = random(0, maxOffset * 2) - maxOffset + floor(size / 2); - const length = random(1, floor(size / 2 - 1)); + const xIndex = random(0, maxOffset * 2) - maxOffset + Math.floor(size / 2); + const length = random(1, Math.floor(size / 2 - 1)); board[xIndex] = board[xIndex].map((point, index) => (index < length ? null : point));