-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsudoku.rb
82 lines (65 loc) · 1.43 KB
/
sudoku.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
class Sudoku
def initialize(problem=nil)
@problem = problem
end
def []=(x, y, i)
@problem[y][x] = i
end
def clone
Sudoku.new Marshal.load(Marshal.dump(@problem))
end
def import_problem(file_name)
@problem = File.open(file_name).readlines.map do |row|
row.chomp.split('').map { |cell| cell.to_i }
end
end
def print_problem
puts @problem.map { |row| row.join ' ' }
end
def solve!
x, y = unknown = next_unknown
return self unless unknown
successors(x, y).each do |i|
successor = clone
successor[x, y] = i
solution = successor.solve!
return solution if solution
end
false
end
private
def next_unknown
@problem.each_with_index do |row, y|
row.each_with_index do |cell, x|
return [x, y] if cell == 0
end
end
nil
end
def successors(x, y)
possible_values - col_members(x) - row_members(y) - group_members(x, y)
end
def possible_values
(1..problem_size).to_a
end
def col_members(x)
@problem.map { |row| row[x] }
end
def row_members(y)
@problem[y]
end
def group_members(x, y)
@problem[group_range(y)].map { |row| row[group_range(x)] }.flatten
end
def group_range(n)
low = n / group_size * group_size
high = low + group_size - 1
low..high
end
def group_size
@group_size ||= Math.sqrt(problem_size).floor
end
def problem_size
@problem.size
end
end