-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsolveSudoku.go
121 lines (108 loc) · 1.99 KB
/
solveSudoku.go
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
package sudokusolver
func solveSudoku(board [][]byte) {
b := newBoard()
for x, cs := range board {
for y, n := range cs {
if n != '.' {
b.checkCell(x, y, n-'0')
}
}
}
if b = b.pass(); b != nil {
for x, cs := range b {
for y, c := range cs {
if board[x][y] == '.' {
board[x][y] = c.value() + '0'
}
}
}
}
}
const cellChecked = cell(1 << 15) // use 15 bit
type cell uint16 // use only 1~9 bits
// checked pass the board check
func (c cell) checked() bool {
return (c & cellChecked) != 0
}
// value get the unique value
func (c cell) value() byte {
c &^= cellChecked
r := cell(1)
for i := byte(1); i <= 9; i++ {
if r == c {
return i
}
r <<= 1
}
return 0
}
type board [][]cell
func newBoard() board {
ret := make(board, 9)
for idx := range ret {
ret[idx] = make([]cell, 9)
for i := range ret[idx] {
ret[idx][i] = (1 << 9) - 1
}
}
return ret
}
func (b board) checkCell(x, y int, v byte) {
mask := cell(1 << (v - 1))
// excludes others
for i := 0; i < 9; i++ {
b[x][i] &^= mask
b[i][y] &^= mask
}
sx := x / 3 * 3
sy := y / 3 * 3
for i := sx; i < sx+3; i++ {
for j := sy; j < sy+3; j++ {
b[i][j] &^= mask
}
}
b[x][y] = mask | cellChecked // set cell(x, y) checked
}
func (b board) pass() board {
for changed := true; changed; {
changed = false
for x, cs := range b {
for y, c := range cs {
if c == 0 {
return nil
} else if c.checked() {
} else if n := c.value(); n > 0 {
b.checkCell(x, y, n)
changed = true
}
}
}
}
for x, cs := range b {
for y, c := range cs {
if !c.checked() {
for k := byte(0); k < 9; k++ {
if (c & (1 << k)) != 0 {
cb := b.clone()
cb.checkCell(x, y, k+1)
if cb = cb.pass(); cb != nil {
return cb
}
}
}
return nil
}
}
}
return b
}
func (b board) clone() board {
ret := make(board, 9)
for idx := range ret {
ret[idx] = make([]cell, 9)
for i := range ret[idx] {
ret[idx][i] = b[idx][i]
}
}
return ret
}