Skip to content

Instantly share code, notes, and snippets.

@alekxeyuk
Created July 20, 2025 15:22
Show Gist options
  • Select an option

  • Save alekxeyuk/d2584dbd26be358d62cc38b623d0b8d9 to your computer and use it in GitHub Desktop.

Select an option

Save alekxeyuk/d2584dbd26be358d62cc38b623d0b8d9 to your computer and use it in GitHub Desktop.
/* 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