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