UNPKG

battleship-ai

Version:

This repository contains a Battleship AI implementation built in TypeScript. The AI focuses on grid-based probability calculations, strategic ship placement, and targeted attack mechanisms to effectively play the game. This README explains the AI’s logic,

1 lines 21.3 kB
{"version":3,"sources":["../src/types/index.ts","../src/grid.ts","../src/index.ts"],"sourcesContent":["export enum CellType {\n\tEmpty = 0, // Water (empty)\n\tMiss = 2, // Missed shot\n\tHit = 3, // Hit ship\n}\n\nexport interface Ship {\n\tsize: number;\n\tpositions: { x: number; y: number }[]; // List of occupied positions\n}\n\nexport interface Coordinate {\n\tx: number;\n\ty: number;\n}\n\nexport interface AttackOutcome extends Coordinate {\n\toutcome: 'hit' | 'miss';\n}\n","/* eslint-disable @typescript-eslint/no-non-null-assertion -- safe */\nimport { CellType } from './types';\n\nexport class Grid {\n\tsize: number;\n\tcells: CellType[][];\n\n\tconstructor(size: number) {\n\t\tthis.size = size;\n\t\tthis.cells = [];\n\t\tthis.init();\n\t}\n\n\tprivate init(): void {\n\t\tfor (let x = 0; x < this.size; x++) {\n\t\t\tconst row: CellType[] = [];\n\t\t\tthis.cells[x] = row;\n\t\t\tfor (let y = 0; y < this.size; y++) {\n\t\t\t\trow.push(CellType.Empty);\n\t\t\t}\n\t\t}\n\t}\n\n\tupdateCell(x: number, y: number, type: CellType): void {\n\t\tthis.cells[x]![y] = type;\n\t}\n\n\tisMiss(x: number, y: number): boolean {\n\t\treturn this.cells[x]![y] === CellType.Miss;\n\t}\n\n\tisDamagedShip(x: number, y: number): boolean {\n\t\treturn this.cells[x]![y] === CellType.Hit;\n\t}\n}\n","/* eslint-disable @typescript-eslint/no-non-null-assertion -- safe */\nimport { Grid } from \"./grid\";\nimport {\n\ttype AttackOutcome,\n\tCellType,\n\ttype Coordinate,\n\ttype Ship,\n} from \"./types\";\n\nexport class BattleShipAI {\n\tprivate probGrid: number[][];\n\tprivate virtualGrid: Grid;\n\tprivate ships: number[];\n\n\tconstructor(gameSize: number, ships: number[]) {\n\t\tthis.virtualGrid = new Grid(gameSize);\n\t\tthis.ships = ships;\n\n\t\tthis.probGrid = [];\n\t\tthis.initProbs(gameSize);\n\t}\n\n\tprivate static readonly PROB_WEIGHT = 5000; // Arbitrarily big number\n\tprivate static readonly OPEN_LOW_MIN = 10;\n\tprivate static readonly OPEN_LOW_MAX = 20;\n\tprivate static readonly OPEN_MED_MIN = 15;\n\tprivate static readonly OPEN_MED_MAX = 25;\n\tprivate static readonly OPEN_HIGH_MIN = 20;\n\tprivate static readonly OPEN_HIGH_MAX = 30;\n\n\tprivate static readonly OPENINGS = [\n\t\t{ x: 7, y: 3, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 6, y: 2, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 3, y: 7, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 2, y: 6, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 6, y: 6, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 3, y: 3, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 5, y: 5, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 4, y: 4, weight: getRandom(this.OPEN_LOW_MIN, this.OPEN_LOW_MAX) },\n\t\t{ x: 0, y: 8, weight: getRandom(this.OPEN_MED_MIN, this.OPEN_MED_MAX) },\n\t\t{ x: 1, y: 9, weight: getRandom(this.OPEN_HIGH_MIN, this.OPEN_HIGH_MAX) },\n\t\t{ x: 8, y: 0, weight: getRandom(this.OPEN_MED_MIN, this.OPEN_MED_MAX) },\n\t\t{ x: 9, y: 1, weight: getRandom(this.OPEN_HIGH_MIN, this.OPEN_HIGH_MAX) },\n\t\t{ x: 9, y: 9, weight: getRandom(this.OPEN_HIGH_MIN, this.OPEN_HIGH_MAX) },\n\t\t{ x: 0, y: 0, weight: getRandom(this.OPEN_HIGH_MIN, this.OPEN_HIGH_MAX) },\n\t];\n\n\t// Initializes the probability grid\n\tprivate initProbs(size: number): void {\n\t\tthis.probGrid = Array.from({ length: size }, () =>\n\t\t\tArray.from({ length: size }, () => 0),\n\t\t);\n\t}\n\n\tprivate setProbs(value: number): void {\n\t\tfor (let x = 0; x < this.virtualGrid.size; x++) {\n\t\t\tfor (let y = 0; y < this.virtualGrid.size; y++) {\n\t\t\t\tthis.probGrid[x][y] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateGrid(moves: AttackOutcome[]): void {\n\t\tthis.resetGrid();\n\t\tmoves.forEach((move) => {\n\t\t\tthis.virtualGrid.updateCell(\n\t\t\t\tmove.x,\n\t\t\t\tmove.y,\n\t\t\t\tmove.outcome === \"hit\" ? CellType.Hit : CellType.Miss,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate resetGrid(): void {\n\t\tfor (let x = 0; x < this.virtualGrid.size; x++) {\n\t\t\tfor (let y = 0; y < this.virtualGrid.size; y++) {\n\t\t\t\tthis.virtualGrid.updateCell(x, y, CellType.Empty);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Resets the probability grid\n\tprivate resetProbs(): void {\n\t\tthis.initProbs(this.virtualGrid.size);\n\t}\n\n\tprivate isValidCell(x: number, y: number): boolean {\n\t\treturn (\n\t\t\tx >= 0 && y >= 0 && x < this.virtualGrid.size && y < this.virtualGrid.size\n\t\t);\n\t}\n\n\tprivate canPlaceShip(\n\t\tx: number,\n\t\ty: number,\n\t\tlength: number,\n\t\tdirection: \"vertical\" | \"horizontal\",\n\t): boolean {\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tconst nx = x + (direction === \"horizontal\" ? i : 0);\n\t\t\tconst ny = y + (direction === \"vertical\" ? i : 0);\n\n\t\t\tif (\n\t\t\t\t!this.isValidCell(nx, ny) ||\n\t\t\t\tthis.virtualGrid.cells[nx]![ny] === CellType.Miss\n\t\t\t) {\n\t\t\t\treturn false; // Can't place a ship here if out of bounds or overlapping a miss.\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Updates the probability grid based on ship positions and previous outcomes\n\tupdateProbs(previousAttacks: AttackOutcome[]): void {\n\t\tthis.updateGrid(previousAttacks);\n\t\tthis.resetProbs();\n\n\t\t// Apply the AI opening patterns\n\t\tfor (const cell of BattleShipAI.OPENINGS) {\n\t\t\tif (cell.x < this.virtualGrid.size && cell.y < this.virtualGrid.size) {\n\t\t\t\tif (this.probGrid[cell.x]![cell.y]! !== 0) {\n\t\t\t\t\tthis.probGrid[cell.x]![cell.y]! += cell.weight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (let x = 0; x < this.virtualGrid.size; x++) {\n\t\t\tfor (let y = 0; y < this.virtualGrid.size; y++) {\n\t\t\t\tif (this.virtualGrid.cells[x]![y] === CellType.Hit) {\n\t\t\t\t\t// For a hit, consider adjacent tiles for continuation of a ship.\n\t\t\t\t\tthis.evaluateAdjacentTiles(x, y);\n\t\t\t\t} else if (this.virtualGrid.cells[x]![y] === CellType.Empty) {\n\t\t\t\t\t// For empty tiles, consider all possible ships fitting through this cell.\n\t\t\t\t\tthis.evaluateCellForShips(x, y);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Adjust probabilities to avoid already attacked cells\n\t\tfor (const attack of previousAttacks) {\n\t\t\tthis.probGrid[attack.x]![attack.y] = 0; // Prevent re-targeting\n\t\t}\n\n\t\t// Adjust if all tiles are attacked\n\t\tconst hitTiles = previousAttacks.filter((a) => a.outcome === \"hit\").length;\n\t\tif (hitTiles === this.ships.reduce((a, b) => a + b, 0)) {\n\t\t\tthis.setProbs(0);\n\t\t}\n\t}\n\n\tprivate evaluateAdjacentTiles(hitX: number, hitY: number): void {\n\t\tconst directions = [\n\t\t\t{ dx: 1, dy: 0 }, // Horizontal right\n\t\t\t{ dx: -1, dy: 0 }, // Horizontal left\n\t\t\t{ dx: 0, dy: 1 }, // Vertical down\n\t\t\t{ dx: 0, dy: -1 }, // Vertical up\n\t\t];\n\n\t\tfor (const { dx, dy } of directions) {\n\t\t\tlet nx = hitX + dx;\n\t\t\tlet ny = hitY + dy;\n\n\t\t\t// Check if the adjacent cell is valid and empty\n\t\t\twhile (\n\t\t\t\tthis.isValidCell(nx, ny) &&\n\t\t\t\tthis.virtualGrid.cells[nx]![ny] === CellType.Empty\n\t\t\t) {\n\t\t\t\tthis.probGrid[nx]![ny]! += BattleShipAI.PROB_WEIGHT; // Assign higher probability to tiles adjacent to hits\n\t\t\t\tnx += dx;\n\t\t\t\tny += dy;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate numHitCellsCovered(coords: Coordinate[]): number {\n\t\treturn coords.reduce((count, coord) => {\n\t\t\treturn this.virtualGrid.cells[coord.x]![coord.y] === CellType.Hit\n\t\t\t\t? count + 1\n\t\t\t\t: count;\n\t\t}, 0);\n\t}\n\n\tprivate getShipCoordinates(\n\t\tx: number,\n\t\ty: number,\n\t\tlength: number,\n\t\tdirection: \"horizontal\" | \"vertical\",\n\t): Coordinate[] {\n\t\tconst coords: Coordinate[] = [];\n\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tif (direction === \"horizontal\") {\n\t\t\t\tcoords.push({ x: x + i, y });\n\t\t\t} else {\n\t\t\t\tcoords.push({ x, y: y + i });\n\t\t\t}\n\t\t}\n\n\t\treturn coords;\n\t}\n\n\tprivate evaluateCellForShips(x: number, y: number): void {\n\t\tfor (const ship of this.ships) {\n\t\t\tconst directions = [\"horizontal\", \"vertical\"] as const;\n\n\t\t\tfor (const direction of directions) {\n\t\t\t\tif (this.canPlaceShip(x, y, ship, direction)) {\n\t\t\t\t\tconst coords = this.getShipCoordinates(x, y, ship, direction);\n\n\t\t\t\t\t// Check if the ship passes through hit cells\n\t\t\t\t\tconst hitCount = this.numHitCellsCovered(coords);\n\t\t\t\t\tconst baseProbability = 1;\n\n\t\t\t\t\tif (hitCount > 0) {\n\t\t\t\t\t\t// Add weight based on the number of hits covered\n\t\t\t\t\t\tfor (const coord of coords) {\n\t\t\t\t\t\t\tthis.probGrid[coord.x]![coord.y]! +=\n\t\t\t\t\t\t\t\tbaseProbability + hitCount * BattleShipAI.PROB_WEIGHT;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Increment probability for empty cells\n\t\t\t\t\t\tfor (const coord of coords) {\n\t\t\t\t\t\t\tthis.probGrid[coord.x]![coord.y]! += baseProbability;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get the coordinates of the highest probability cell\n\tgetHighestProbabilityTarget(previousMoves: AttackOutcome[]): {\n\t\tx: number;\n\t\ty: number;\n\t} {\n\t\tthis.updateProbs(previousMoves);\n\n\t\tlet maxProb = -1;\n\t\tconst maxProbs: Coordinate[] = [];\n\n\t\tfor (let x = 0; x < this.probGrid.length; x++) {\n\t\t\tfor (let y = 0; y < this.probGrid[x]!.length; y++) {\n\t\t\t\tif (this.probGrid[x]![y]! > maxProb) {\n\t\t\t\t\tmaxProb = this.probGrid[x]![y]!;\n\t\t\t\t\tmaxProbs.length = 0; // Clear previous maxProb cells\n\t\t\t\t\tmaxProbs.push({ x, y });\n\t\t\t\t} else if (this.probGrid[x]![y] === maxProb) {\n\t\t\t\t\tmaxProbs.push({ x, y });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (maxProb === 0) {\n\t\t\treturn { x: -1, y: -1 }; // All cells are attacked\n\t\t}\n\n\t\t// Return a random choice among cells with the highest probability\n\t\treturn maxProbs[Math.floor(Math.random() * maxProbs.length)]!;\n\t}\n\n\tpublic getHeatmap(): number[][] {\n\t\treturn this.probGrid;\n\t}\n\n\tpublic getRandomShipPlacements(): Ship[] {\n\t\tconst ships: Ship[] = [];\n\t\tconst inner = Array<string>(this.virtualGrid.size).fill(\"empty\");\n\t\tconst board: string[][] = Array.from(\n\t\t\t{ length: this.virtualGrid.size },\n\t\t\t() => [...inner],\n\t\t);\n\n\t\t// Function to check if the ship can be placed at the specified position\n\t\tconst isValidPlacement = (\n\t\t\tx: number,\n\t\t\ty: number,\n\t\t\tsize: number,\n\t\t\tisHorizontal: boolean,\n\t\t): boolean => {\n\t\t\tif (isHorizontal) {\n\t\t\t\tif (x + size > this.virtualGrid.size) return false; // Ship exceeds board width\n\t\t\t\tfor (let i = 0; i < size; i++) {\n\t\t\t\t\tif (board[y]![x + i]! !== \"empty\") return false; // Cell is already occupied\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (y + size > this.virtualGrid.size) return false; // Ship exceeds board height\n\t\t\t\tfor (let i = 0; i < size; i++) {\n\t\t\t\t\tif (board[y + i]![x]! !== \"empty\") return false; // Cell is already occupied\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\n\t\t// Function to find all valid positions for a ship of given size and orientation\n\t\tconst findValidPositions = (\n\t\t\tsize: number,\n\t\t): { x: number; y: number; isHorizontal: boolean }[] => {\n\t\t\tconst validPositions: { x: number; y: number; isHorizontal: boolean }[] =\n\t\t\t\t[];\n\t\t\tfor (let x = 0; x < this.virtualGrid.size; x++) {\n\t\t\t\tfor (let y = 0; y < this.virtualGrid.size; y++) {\n\t\t\t\t\tif (isValidPlacement(x, y, size, true)) {\n\t\t\t\t\t\t// Horizontal placement\n\t\t\t\t\t\tvalidPositions.push({ x, y, isHorizontal: true });\n\t\t\t\t\t}\n\t\t\t\t\tif (isValidPlacement(x, y, size, false)) {\n\t\t\t\t\t\t// Vertical placement\n\t\t\t\t\t\tvalidPositions.push({ x, y, isHorizontal: false });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn validPositions;\n\t\t};\n\n\t\t// Function to place a ship at a valid position\n\t\tconst placeShip = (size: number): Ship => {\n\t\t\tconst ship: Ship = { size, positions: [] };\n\t\t\tconst validPositions = findValidPositions(size);\n\t\t\tif (validPositions.length === 0) {\n\t\t\t\tthrow new Error(`No valid placements for ship of size ${String(size)}`);\n\t\t\t}\n\n\t\t\t// Randomly select one valid placement\n\t\t\tconst randomPosition =\n\t\t\t\tvalidPositions[Math.floor(Math.random() * validPositions.length)];\n\t\t\tconst { x, y, isHorizontal } = randomPosition!;\n\n\t\t\t// Place the ship on the board\n\t\t\tfor (let i = 0; i < size; i++) {\n\t\t\t\tif (isHorizontal) {\n\t\t\t\t\tboard[y]![x + i] = \"ship\";\n\t\t\t\t\tship.positions.push({ x: x + i, y });\n\t\t\t\t} else {\n\t\t\t\t\tboard[y + i]![x] = \"ship\";\n\t\t\t\t\tship.positions.push({ x, y: y + i });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ship;\n\t\t};\n\n\t\t// Place each ship\n\t\tfor (const ship of this.ships) {\n\t\t\tships.push(placeShip(ship));\n\t\t}\n\n\t\treturn ships;\n\t}\n\n\tpublic calculateOutcome(x: number, y: number, ships: Ship[]): \"hit\" | \"miss\" {\n\t\tfor (const ship of ships) {\n\t\t\tfor (const position of ship.positions) {\n\t\t\t\tif (position.x === x && position.y === y) {\n\t\t\t\t\treturn \"hit\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn \"miss\";\n\t}\n}\n\n// Utility function to get a random number between min and max\nfunction getRandom(min: number, max: number): number {\n\treturn Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\nexport { Grid };\nexport * from \"./types\";\n"],"mappings":"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","names":["CellType"]}