-
Notifications
You must be signed in to change notification settings - Fork 0
/
dfs.jl
114 lines (94 loc) · 2.28 KB
/
dfs.jl
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
"""
Depth first search
- Select first empty element starting top left
- Check through 1, 2, ... 9 until valid number found
- Classic backtracking approach
"""
function solveDFS!(s::Sudoku)
distToFirstDigit = fill(0, 8)
for i in 0 : 7
distToFirstDigit[i + 1] = findDigit(Sudoku(rotate(s.field, i)))
end
rot = findmin(distToFirstDigit)[2] - 1 # optimal rotation for dfs
sRot = Sudoku(rotate(s.field, rot))
if (rot == 3) # rotate(rotate(p, i), i) = p for all i except 1, 3
rot = 1
elseif (rot == 1)
rot = 3
end
backtrackDFS!(sRot)
sOut = rotate(sRot.field, rot)
for i in 1 : 9
for j in 1 : 9
s.field[i, j] = sOut[i, j]
end
end
end
function backtrackDFS!(s::Sudoku)
x, y = findEmpty(s)
if (x == 0 && y == 0) # sudoku filled
return true
end
for i in 1 : 9
if (check(s, x, y, i))
s.field[x, y] = i
if (backtrackDFS!(s))
return true
end
s.field[x, y] = 0
end
end
return false
end
@inline function rotate(p::Matrix, d::Int64)
if d <= 3
return rotl90(p, d)
else
return reverse(rotl90(p, d - 4), dims=2)
end
end
@inline function findDigit(s::Sudoku)
for i in 1 : 9
for j in 1 : 9
if (s.field[i, j] != 0)
return j + (i - 1) * 9
end
end
end
end
# find first empty field in s
@inline function findEmpty(s::Sudoku)
for i in 1 : 9
for j in 1 : 9
if (s.field[i, j] == 0)
return i, j
end
end
end
return 0, 0
end
@inline function check(s::Sudoku, x::Int64, y::Int64, value::Int64)
for i in 1 : 9 # check row
if (i != y && s.field[x, i] == value)
return false
end
end
for i in 1 : 9 # check column
if (i != x && s.field[i, y] == value)
return false
end
end
# check groups
cornerX = x - (x - 1) % 3
cornerY = y - (y - 1) % 3
for i in 0 : 2
for j in 0 : 2
if (i != x || j != y)
if (s.field[cornerX + i, cornerY + j] == value)
return false
end
end
end
end
return true
end