/** * Generate a fully valid Sudoku solution using a base pattern and structural shuffles. * Returns a string of 81 digits (row-major order). */ export function generateSolvedBoard(): string { const size = 9; const box = 3; // --- 1️⃣ Base pattern function --- const pattern = (r: number, c: number) => (box * (r % box) + Math.floor(r / box) + c) % size; // --- 2️⃣ Create base board --- const baseBoard: number[][] = Array.from({ length: size }, (_, r) => Array.from({ length: size }, (_, c) => pattern(r, c) + 1) ); // --- 3️⃣ Helper to shuffle an array in place --- const shuffle = (arr: T[]): T[] => { const copy = [...arr]; for (let i = copy.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [copy[i], copy[j]] = [copy[j], copy[i]]; } return copy; }; // --- 4️⃣ Build shuffled row/col indices preserving 3×3 structure --- const rows = shuffle([0, 1, 2]) .concat(shuffle([3, 4, 5])) .concat(shuffle([6, 7, 8])); const cols = shuffle([0, 1, 2]) .concat(shuffle([3, 4, 5])) .concat(shuffle([6, 7, 8])); // --- 5️⃣ Shuffle entire bands and stacks (groups of 3) --- const rowBands = shuffle([0, 1, 2]); const colStacks = shuffle([0, 1, 2]); const shuffledRows = rowBands.flatMap(band => rows.slice(band * 3, band * 3 + 3)); const shuffledCols = colStacks.flatMap(stack => cols.slice(stack * 3, stack * 3 + 3)); // --- 6️⃣ Digit permutation (1–9) --- const digits = shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]); // --- 7️⃣ Build the final shuffled board --- const board: number[][] = shuffledRows.map(r => shuffledCols.map(c => digits[baseBoard[r][c] - 1]) ); // --- 8️⃣ Flatten to 81-char string --- return board.flat().join(''); }