import { mulberry32, type IsotypeCell } from './patterns'; /** Row-major 3x3 grid (9 cells) — a tuple so every pattern is guaranteed complete at compile time. */ export type IsotypeMiniPattern = readonly [ IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, IsotypeCell, ]; /** Widen this union as new 3x3 isotypes join the series. */ export type IsotypeMiniPatternId = 'core'; export const ISOTYPE_MINI_PATTERNS: Record = { core: [ 'purple', 'blue', 'blue', 'magenta', 'yellow', 'green', 'magenta', 'red', 'brown', ], }; export const ISOTYPE_MINI_PATTERN_IDS = Object.keys( ISOTYPE_MINI_PATTERNS ) as IsotypeMiniPatternId[]; /** * Returns a copy of the given pattern with exactly one cell (chosen * deterministically from `seed`) swapped to `'blank'`. Pure — the same * `(patternId, seed)` pair always returns the same result. Unlike * `getIsotypeVariant`, the mini patterns have no inherent blank cell, so * every cell is a candidate. */ export function getIsotypeMiniVariant( patternId: IsotypeMiniPatternId, seed: number ): IsotypeMiniPattern { const base = ISOTYPE_MINI_PATTERNS[patternId]; const candidateIndices = base.reduce( (acc, cell, i) => (cell === 'blank' ? acc : [...acc, i]), [] ); const rng = mulberry32(seed); const chosen = candidateIndices[Math.floor(rng() * candidateIndices.length)]; return base.map((cell, i) => (i === chosen ? 'blank' : cell)) as unknown as IsotypeMiniPattern; }