import { isBoardCoordInBounds } from '../board.ts' export type WinDirection = readonly [number, number] export interface WinMask { readonly cellIndices: readonly number[] readonly beforeIndex: number | null readonly afterIndex: number | null readonly direction: WinDirection readonly words: Uint32Array } export interface WinMaskSet { readonly boardSize: number readonly cellCount: number readonly wordCount: number readonly masks: readonly WinMask[] readonly byCellIndex: readonly (readonly WinMask[])[] } const DIRECTIONS: readonly WinDirection[] = [[1, 0], [0, 1], [1, 1], [1, -1]] const cache = new Map() export function getWinMasks(boardSize: number): WinMaskSet { const cached = cache.get(boardSize) if (cached) return cached const cellCount = boardSize * boardSize const wordCount = Math.ceil(cellCount / 32) const masks: WinMask[] = [] const byCellIndex: WinMask[][] = Array.from({ length: cellCount }, () => []) for (const direction of DIRECTIONS) { const [dx, dy] = direction for (let y = 0; y < boardSize; y++) { for (let x = 0; x < boardSize; x++) { const endX = x + dx * 4 const endY = y + dy * 4 if (!isBoardCoordInBounds(endX, endY, boardSize)) continue const cellIndices: number[] = [] const words = new Uint32Array(wordCount) for (let i = 0; i < 5; i++) { const index = toIndex(x + dx * i, y + dy * i, boardSize) cellIndices.push(index) words[index >>> 5] |= 1 << (index & 31) } const beforeX = x - dx const beforeY = y - dy const afterX = x + dx * 5 const afterY = y + dy * 5 const mask: WinMask = { cellIndices, beforeIndex: isBoardCoordInBounds(beforeX, beforeY, boardSize) ? toIndex(beforeX, beforeY, boardSize) : null, afterIndex: isBoardCoordInBounds(afterX, afterY, boardSize) ? toIndex(afterX, afterY, boardSize) : null, direction, words, } masks.push(mask) for (const index of cellIndices) byCellIndex[index].push(mask) } } } const result: WinMaskSet = { boardSize, cellCount, wordCount, masks, byCellIndex } cache.set(boardSize, result) return result } function toIndex(x: number, y: number, boardSize: number): number { return y * boardSize + x }