/** * Validate a fully filled Sudoku board (81-char string) * Returns true if: * - 81 characters long * - all characters are digits 1–9 * - all rows, columns, and 3×3 boxes sum to 45 */ export function validateFullBoard(board: string): boolean { // --- Basic sanity --- if (board.length !== 81) return false; if (!/^[1-9]+$/.test(board)) return false; const getCell = (r: number, c: number) => Number(board[r * 9 + c]); // --- Validate rows --- for (let r = 0; r < 9; r++) { const sum = Array.from({ length: 9 }, (_, c) => getCell(r, c)) .reduce((a, b) => a + b, 0); if (sum !== 45) return false; } // --- Validate columns --- for (let c = 0; c < 9; c++) { const sum = Array.from({ length: 9 }, (_, r) => getCell(r, c)) .reduce((a, b) => a + b, 0); if (sum !== 45) return false; } // --- Validate 3×3 boxes --- for (let br = 0; br < 3; br++) { for (let bc = 0; bc < 3; bc++) { const sum = Array.from({ length: 9 }, (_, i) => { const r = br * 3 + Math.floor(i / 3); const c = bc * 3 + (i % 3); return getCell(r, c); }).reduce((a, b) => a + b, 0); if (sum !== 45) return false; } } return true; } /** * 🔍 Assert that a Sudoku board string represents a valid, fully filled grid. * * Format: * - 81 characters * - Only digits 1–9 * - Each row, column, and 3×3 box contains unique digits that sum to 45 * * Throws descriptive errors on failure. */ export function assertValidFullBoard(board: string): void { // --- Basic integrity checks --- console.assert(board.length === 81, `❌ Board length must be 81, got ${board.length}`); if (board.length !== 81) throw new Error(`Invalid board length: ${board.length}`); // All characters must be digits 1–9 console.assert(/^[1-9]+$/.test(board), "❌ Board must contain only digits 1–9 (no 0s or dots)"); if (!/^[1-9]+$/.test(board)) throw new Error("Board contains invalid characters"); const get = (r: number, c: number) => Number(board[r * 9 + c]); // --- Helper to assert uniqueness and sum --- const assertGroup = (label: string, cells: number[]) => { const sum = cells.reduce((a, b) => a + b, 0); const unique = new Set(cells); console.assert(sum === 45, `❌ ${label} sum=${sum} (should be 45)`); console.assert(unique.size === 9, `❌ ${label} has duplicates: [${cells.join(",")}]`); if (sum !== 45) throw new Error(`${label} does not sum to 45`); if (unique.size !== 9) throw new Error(`${label} contains duplicates`); }; // --- Validate rows --- for (let r = 0; r < 9; r++) { const row = Array.from({ length: 9 }, (_, c) => get(r, c)); assertGroup(`Row ${r + 1}`, row); } // --- Validate columns --- for (let c = 0; c < 9; c++) { const col = Array.from({ length: 9 }, (_, r) => get(r, c)); assertGroup(`Column ${c + 1}`, col); } // --- Validate 3×3 boxes --- for (let br = 0; br < 3; br++) { for (let bc = 0; bc < 3; bc++) { const box: number[] = []; for (let r = 0; r < 3; r++) { for (let c = 0; c < 3; c++) { box.push(get(br * 3 + r, bc * 3 + c)); } } const idx = br * 3 + bc + 1; assertGroup(`Box ${idx}`, box); } } }