Created
July 20, 2025 15:22
-
-
Save alekxeyuk/d2584dbd26be358d62cc38b623d0b8d9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* parseSudokuBoard() | |
| Reads the live DOM and returns a 9×9 array: | |
| – null for an empty cell | |
| – 1-9 for a filled cell | |
| */ | |
| function parseSudokuBoard() { | |
| const board = Array.from({ | |
| length: 9 | |
| }, () => Array(9).fill(null)); | |
| // All cell wrappers (empty or filled) live inside .GameBoardGrid_row__AwPF4 | |
| document.querySelectorAll("[class^='GameBoardGrid_row']").forEach((rowEl, r) => { | |
| rowEl.querySelectorAll("[class^='GameBoardGrid_cell']").forEach((cellWrapper, c) => { | |
| const inner = cellWrapper.querySelector("[class^='GameBoardCell_cell']"); | |
| if (!inner) return; // should never happen | |
| const filled = inner.childElementCount !== 0; | |
| if (filled) { | |
| const p = inner.querySelector("p[class^='GameBoardCell_cellValue']"); | |
| if (p) { | |
| const n = parseInt(p.textContent, 10); | |
| if (n >= 1 && n <= 9) board[r][c] = n; | |
| } | |
| } else { | |
| board[r][c] = null; // empty cell | |
| } | |
| }); | |
| }); | |
| return board; | |
| } | |
| function solveSudoku(board) { | |
| // Deep-clone so we don’t mutate the original | |
| const grid = board.map(r => [...r]); | |
| /* ---------- helpers ---------- */ | |
| const inRow = (r, n) => grid[r].includes(n); | |
| const inCol = (c, n) => grid.some(row => row[c] === n); | |
| function inBox(r, c, n) { | |
| const br = Math.floor(r / 3) * 3; | |
| const bc = Math.floor(c / 3) * 3; | |
| for (let i = 0; i < 3; i++) | |
| for (let j = 0; j < 3; j++) | |
| if (grid[br + i][bc + j] === n) return true; | |
| return false; | |
| } | |
| function findEmpty() { | |
| for (let r = 0; r < 9; r++) | |
| for (let c = 0; c < 9; c++) | |
| if (grid[r][c] === null) return [r, c]; | |
| return null; | |
| } | |
| function backtrack() { | |
| const pos = findEmpty(); | |
| if (!pos) return true; // solved | |
| const [r, c] = pos; | |
| for (let n = 1; n <= 9; n++) { | |
| if (!inRow(r, n) && !inCol(c, n) && !inBox(r, c, n)) { | |
| grid[r][c] = n; | |
| if (backtrack()) return true; | |
| grid[r][c] = null; // undo | |
| } | |
| } | |
| return false; | |
| } | |
| backtrack(); // modifies grid in-place | |
| return grid; | |
| } | |
| /* | |
| * Autofills the live Sudoku grid on the page. | |
| * 1. Reads the current grid state. | |
| * 2. Solves it. | |
| * 3. For every empty cell (null in the matrix) it: | |
| * – clicks the cell wrapper (<div class="GameBoardGrid_cell__…">) | |
| * – clicks the correct number button (1-9) | |
| * Uses only already-existing DOM elements, no direct value injection. | |
| */ | |
| (async function autoSolveAndFill() { | |
| /* ---------- 1. get current board ---------- */ | |
| const board = parseSudokuBoard(); | |
| /* ---------- 2. solve ---------- */ | |
| const solved = solveSudoku(board); | |
| /* ---------- 3. helpers ---------- */ | |
| const rows = document.querySelectorAll("[class^='GameBoardGrid_row']"); | |
| const numberButtons = document.querySelectorAll("button[class*='GameInputNumber_number']"); | |
| // Build quick lookup: value → button | |
| const btnMap = {}; | |
| numberButtons.forEach(btn => { | |
| const val = parseInt(btn.textContent.trim(), 10); | |
| if (val >= 1 && val <= 9) btnMap[val] = btn; | |
| }); | |
| /* small delay helper so the browser can repaint between clicks */ | |
| const sleep = ms => new Promise(r => setTimeout(r, ms)); | |
| /* ---------- 4. fill empty cells ---------- */ | |
| for (let r = 0; r < 9; r++) { | |
| for (let c = 0; c < 9; c++) { | |
| if (board[r][c] !== null) continue; // already filled | |
| const correctValue = solved[r][c]; | |
| if (!btnMap[correctValue]) continue; // should never happen | |
| /* cell wrapper to click */ | |
| const cellWrapper = rows[r].children[c]; | |
| if (!cellWrapper) continue; | |
| /* click cell, then click the number button */ | |
| cellWrapper.children[0].click(); | |
| await sleep(300); // give UI time (tweak if needed) | |
| btnMap[correctValue].click(); | |
| await sleep(300); | |
| } | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment