-
Notifications
You must be signed in to change notification settings - Fork 0
/
sudoku_old.rb
218 lines (190 loc) · 3.99 KB
/
sudoku_old.rb
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
class Cell
attr_accessor :value
attr_reader :possibles
def initialize
@value = nil
@possibles = []
end
def add_possible(value)
@possibles << value if !@possibles.include?(value)
end
def remove_possible(value)
@possibles.delete(value)
end
def clear_possibles
@possibles = []
end
end
class Sudoku
attr_reader :grid
def initialize(grid)
@grid = []
9.times { |i|
@grid[i] = []
9.times { |j|
@grid[i][j] = Cell.new
}
}
9.times { |i|
9.times { |j|
if(!grid[i][j].nil?)
@grid[i][j].value = grid[i][j]
end
}
}
end
def print
9.times { |i|
9.times { |j|
printf("%d ", @grid[i][j].value) if !@grid[i][j].value.nil?
printf("_ ") if @grid[i][j].value.nil?
}
printf "\n"
}
end
end
class Solver
def initialize(soduku)
@soduku = soduku
@grid = soduku.grid
end
def initialize_candidates
# For each box without a value,
# build up a list of candidates
9.times { |i|
9.times { |j|
(1..9).each {|val|
@grid[i][j].add_possible(val) if check_value(val, i, j)
} if @grid[i][j].value.nil?
}
}
end
def solve
cond = true
while cond
initialize_candidates
locked_candidates_1
cond = singles
end
@soduku.print
end
def each_in_row(i)
@grid[i].each { |x|
yield x.value if !x.value.nil?
}
end
def each_in_col(j)
9.times { |i|
x = @grid[i][j]
yield x.value if !x.value.nil?
}
end
def each_in_box(i, j)
box = [(0..2), (3..5), (6..8)]
box.select { |x| x === i }[0].each { |i|
box.select { |x| x === j }[0].each { |j|
yield @grid[i][j].value
}
}
end
def each_box_range
box = [(0..2), (3..5), (6..8)]
box.each { |i|
box.each { |j|
yield i, j # yield the ranges for the box
}
}
end
def check_value(val, i, j)
each_in_row(i) { |x|
return false if x == val
}
each_in_col(j) { |x|
return false if x == val
}
each_in_box(i,j) { |x|
return false if x == val
}
return true
end
=begin
Singles:
Any cells which have one candidate can safley be assigned a
value.
=end
def singles
found_something = false
@grid.each { |row|
row.each { |cell|
if cell.possibles.length == 1
found_something = true
cell.value = cell.possibles[0]
cell.clear_possibles
end
}
}
return found_something
end
=begin
Locked Candidates (1)
look for locked candidates and remove the numbers
from the list of possibles.
=end
def locked_candidates_1
# Look for locked candidates
# these rely on values in other box's only appearing in
# 1 column or row in a box
each_box_range { |i_range, j_range|
(1..9).each { |val|
# the columns and rows these values appear in
# if these == 1 then we have to investigate further
rows = []
columns = []
i_range.each{ |i|
j_range.each {|j|
if @grid[i][j].possibles.include?(val)
rows << i if !rows.include?(i)
columns << j if !columns.include?(i)
end
}
}
if rows.length == 1
# with the exception of cells in
# this j_range, remove all val's
# from the possibles of anything else
# in this row
i = rows[0]
@grid[i].each_index { |j|
if !(j_range === j)
p "removed locked candidate 1 ("+i.to_s+", "+j.to_s+" = "+val.to_s+")"
@grid[i][j].remove_possible(val)
end
}
end
if columns.length == 1
# same as before but for cols
j = columns[0]
9.times { |i|
if !(i_range === i)
p "removed locked candidate 1 ("+i.to_s+", "+j.to_s+" = "+val.to_s+")"
@grid[i][j].remove_possible(val)
end
}
end
}
}
end
end
raw = [
[nil, nil, nil, nil, nil, nil, nil,nil, nil],
[nil, nil, 7, 8, 3, nil, 9, nil, nil],
[nil, nil, 5, nil, nil, 2, 6, 4, nil],
[nil, nil, 2, 6, nil, nil, nil, 7, nil],
[nil, 4, nil, nil, nil, nil, nil, 8, nil],
[nil, 6, nil, nil, nil, 3, 2, nil, nil],
[nil, 2, 8, 4, nil, nil, 5, nil, nil],
[nil, nil, nil, nil, 9, 6, 1, nil, nil],
[nil, nil, nil, nil, nil, nil, nil,nil, nil]
]
s = Solver.new(Sudoku.new(raw))
s.solve