-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolver_functions.R
105 lines (83 loc) · 2.63 KB
/
solver_functions.R
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
solve_sudoku = function(puzzle) {
#' tracks candidate values for each cell
cand = lapply(1:81, function(x){
if(puzzle[x]==0) 1:9
else 0
})
dim(cand) = c(9,9)
#' Prunes constraint; if only one possibility fills into puzzle
#' repeats until convergence
prune = function(puzzle, cand) {
repeat {
changed = FALSE
for(row in 1:9) {
for(col in 1:9) {
if(!all(cand[[row, col]] == 0)) {
#row constraint
cand[[row, col]] = setdiff(cand[[row, col]], puzzle[row, ])
#column constraint
cand[[row, col]] = setdiff(cand[[row, col]], puzzle[, col])
#3x3 box constraint
xmin = col - ((col - 1) %% 3)
xmax = col + ( 3 - (((col - 1) %% 3) + 1) )
ymin = row - ((row - 1) %% 3)
ymax = row + ( 3 - (((row - 1) %% 3) + 1) )
cand[[row, col]] = setdiff(cand[[row, col]], puzzle[ymin:ymax, xmin:xmax])
}
#fill in if only one possibility
if(length(cand[[row, col]]) == 1 & all(cand[[row, col]] != 0)) {
puzzle[row, col] = cand[[row, col]]
cand[[row, col]] = 0
changed = TRUE
}
#empty sets get set to 0
if(length(cand[[row, col]]) == 0) cand[[row, col]] = 0
}
}
if(!changed) break()
}
list(puzzle, cand)
}
#' Finds cell with fewest viable candidates
find_easiest = function(cand) {
easiest = which.min(lapply(cand, function(x){
if(!any(x == 0)) length(x)
else NA
}))
easiest
}
#' depth first search solution
dfs = function(puzzle, cand) {
#prune
pruned = prune(puzzle, cand)
puzzle = pruned[[1]]
cand = pruned[[2]]
#failure
if(sum(as.vector(puzzle == 0) & sapply(cand, function(x){all(x == 0)})) > 0) return(NULL)
#success
if(sum(puzzle == 0) == 0) return(puzzle)
cell_location = find_easiest(cand)
candidates = cand[[cell_location]]
for(x in candidates) {
puzzle[cell_location] = x
cand[[cell_location]] = 0
ans = dfs(puzzle, cand)
if(!is.null(ans)) return(ans)
else candidates = setdiff(candidates, x)
}
return(NULL)
}
dfs(puzzle, cand)
}
puzzle = c(8,0,0,0,0,0,0,0,0,
0,0,7,5,0,0,0,0,9,
0,3,0,0,0,0,1,8,0,
0,6,0,0,0,1,0,5,0,
0,0,9,0,4,0,0,0,0,
0,0,0,7,5,0,0,0,0,
0,0,2,0,7,0,0,0,4,
0,0,0,0,0,3,6,1,0,
0,0,0,0,0,0,8,0,0)
puzzle = matrix(puzzle, nrow = 9)
print(puzzle)
solve_sudoku(puzzle)