lintry

37 sudoku

1 +/**
2 + * @param {character[][]} board
3 + * @return {void} Do not return anything, modify board in-place instead.
4 + */
5 +var solveSudoku = function(board) {
6 + let empty = {};
7 + let rows = new Array(9).fill(void 0).map(()=>new Set());
8 + let cols = new Array(9).fill(void 0).map(()=>new Set());
9 + let blocks = new Array(9).fill(void 0).map(()=>new Set());
10 +
11 + for (let i=0;i<9;i++) {
12 + for (let j = 0; j < 9; j++) {
13 + let block = block_no(i, j);
14 + let v = board[i][j];
15 + if (v !== '.') {
16 + rows[i].add(v);
17 + cols[j].add(v);
18 + blocks[block].add(v);
19 + mark({block, i, j}, v);
20 + } else {
21 + mark({block, i, j}, v);
22 + }
23 + }
24 + }
25 +
26 + function block_no(i, j) {
27 + return (~~(i/3))*3 + ~~(j/3);
28 + }
29 + function mark({block, i, j}, v) {
30 + for (let n=0;n<9;n++){
31 + // not empty cell
32 + if ((i === n || j === n) && v !== '.') {
33 + if (empty[i+','+j]) {
34 + delete empty[i+','+j];
35 + }
36 + continue;
37 + }
38 +
39 + // cols
40 + if (board[i][n] === '.') {
41 + let e = empty[i+','+n] = empty[i+','+n] || {block: block_no(i, n), i, j:n, maybe: new Set(['1','2','3','4','5','6','7','8','9'])};
42 + e.maybe.delete(v);
43 + if (!e.maybe.size) {
44 + delete empty[i+','+n];
45 + }
46 + }
47 +
48 + // rows
49 + if (board[n][j] === '.') {
50 + let e = empty[n+','+j] = empty[n+','+j] || {block: block_no(n, j), i:n, j, maybe: new Set(['1','2','3','4','5','6','7','8','9'])};
51 + e.maybe.delete(v);
52 + if (!e.maybe.size) {
53 + delete empty[n+','+j];
54 + }
55 + }
56 +
57 + // blocks
58 + let bi = ~~(block/3);
59 + let bj = block % 3;
60 + for (let bn=0;bn<9;bn++) {
61 + let i = bi*3 + ~~(bn/3);
62 + let j = bj*3 + bn % 3;
63 + if (board[i][j] === '.') {
64 + let e = empty[i+','+j] = empty[i+','+j] || {block: block_no(i, j), i, j, maybe: new Set(['1','2','3','4','5','6','7','8','9'])};
65 + e.maybe.delete(v);
66 + if (!e.maybe.size) {
67 + delete empty[i+','+j];
68 + }
69 + }
70 + }
71 + }
72 + }
73 +
74 + function fill(i, j, block, v) {
75 + board[i][j] = v;
76 + empty[i+','+j].value = v;
77 + rows[i].add(v);
78 + cols[j].add(v);
79 + blocks[block].add(v);
80 + }
81 +
82 + function unfill(i, j, block, v) {
83 + board[i][j] = '.';
84 + empty[i+','+j].value = void 0;
85 + rows[i].delete(v);
86 + cols[j].delete(v);
87 + blocks[block].delete(v);
88 + }
89 +
90 + function deal() {
91 + let blanks = Object.keys(empty).map(k=>empty[k]).filter(m=>!m.value).sort((a,b)=>{
92 + return a.maybe.size - b.maybe.size;
93 + });
94 +
95 + for (let e of blanks) {
96 + let {block, i, j, value} = e;
97 + if (value) {continue;}
98 + let union = new Set([...rows[i], ...cols[j], ...blocks[block]]);
99 + let maybe = new Set(['1','2','3','4','5','6','7','8','9'].filter(v=>!union.has(v)));
100 +
101 + if (!maybe.size) {
102 + return false;
103 + }
104 + for (let v of [...maybe]) {
105 + // set for testing
106 + if (rows[i].has(v) || cols[j].has(v) || blocks[block].has(v)) {
107 + return false;
108 + }
109 + fill(i, j, block, v);
110 + if (deal()) {
111 + break; // found
112 + } else {
113 + // rollback
114 + unfill(i, j, block, v);
115 + continue; // test next
116 + }
117 + }
118 +
119 + if (board[i][j] === '.') {
120 + return false;
121 + }
122 + }
123 +
124 + return true;
125 + }
126 +
127 + deal();
128 +};
129 +
130 +var sudoku = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]];
131 +solveSudoku(sudoku);
132 +console.info(sudoku);