Class: Grid

Inherits:
Object
  • Object
show all
Defined in:
lib/sudoku_solver/grid.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(txt_file) ⇒ Grid

Returns a new instance of Grid.



6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/sudoku_solver/grid.rb', line 6

def initialize(txt_file)
  @points = []
  txt_file.each_with_index do |text, row|
    text.split("").map(&:to_i).each_with_index do |num, col|
      @points << Point.new(row, col, num)
    end
  end
  
  remaining_points.each do |poi|
    poi.nums = Array(1..9) - (get_box(poi.box) + get_row(poi.y) + get_column(poi.x))
  end
end

Instance Attribute Details

#pointsObject

Returns the value of attribute points.



5
6
7
# File 'lib/sudoku_solver/grid.rb', line 5

def points
  @points
end

#remaining_numsObject

Returns the value of attribute remaining_nums.



5
6
7
# File 'lib/sudoku_solver/grid.rb', line 5

def remaining_nums
  @remaining_nums
end

Instance Method Details

#all_naked_pairsObject



108
109
110
111
112
# File 'lib/sudoku_solver/grid.rb', line 108

def all_naked_pairs
  fill_in
  pinned_points
  naked_pairs
end

#box_count(box, num) ⇒ Object



208
209
210
# File 'lib/sudoku_solver/grid.rb', line 208

def box_count(box, num)
  @points.select { |p| p.box == box && p.nums.to_set.subset?(num.to_set) }.count 
end

#box_line_reductionObject



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/sudoku_solver/grid.rb', line 151

def box_line_reduction
  pointing_pairs
  remaining_points.each do |point|
    (1..9).each do |num|
      [:x, :y].each do |symbol|
        possible = remaining_points.select { |p| p.send(symbol) == point.send(symbol) && p.box == point.box && p.include?(num) }
        if possible.count >= 2
          if @points.select { |p| p.send(symbol) == point.send(symbol) && (!possible.include?(p)) && p.include?(num) }.count == 0
            remove = remaining_points.select { |p| p.box == point.box && p.include?(num) && (!possible.include?(p)) }
            remove.each do |r|
              r.nums = (r.nums - [num])
            end
          end
        end
      end
    end
  end
end

#check_row(row, point, num, symbol) ⇒ Object



239
240
241
242
# File 'lib/sudoku_solver/grid.rb', line 239

def check_row(row, point, num, symbol)
  a = @points.select { |p| p.send(flip(symbol)) == row && p != point  }.map { |x| x.nums }.flatten
  a.count(num) <= 1
end

#compare_points(arr) ⇒ Object



182
183
184
185
186
187
188
# File 'lib/sudoku_solver/grid.rb', line 182

def compare_points(arr)
  a = []
  a << :x if arr.all? { |w| w.x == arr.first.x }
  a << :y if arr.all? { |s| s.y == arr.first.y }
  a << :box if arr.all? { |t| t.box == arr.first.box }
  a
end

#componentsObject



82
83
84
# File 'lib/sudoku_solver/grid.rb', line 82

def components
  [:x, :y, :box]
end

#fill_inObject



71
72
73
74
75
# File 'lib/sudoku_solver/grid.rb', line 71

def fill_in
  remaining_points.each do |p|
    find_diff(p)
  end
end

#fill_row(num) ⇒ Object



44
45
46
# File 'lib/sudoku_solver/grid.rb', line 44

def fill_row(num)
  @points.select { |point| point.x == num  }
end

#find_diff(point) ⇒ Object



48
49
50
# File 'lib/sudoku_solver/grid.rb', line 48

def find_diff(point)
  point.nums = point.nums - (get_box(point.box) + get_row(point.y) + get_column(point.x))
end

#flat_pointsObject



52
53
54
# File 'lib/sudoku_solver/grid.rb', line 52

def flat_points
  @points.select { |p| p.value == 0 }
end

#flip(n) ⇒ Object



244
245
246
247
248
249
250
# File 'lib/sudoku_solver/grid.rb', line 244

def flip(n)
  if n == :y
    :x
  else 
    :y
  end
end

#get_box(num) ⇒ Object



32
33
34
# File 'lib/sudoku_solver/grid.rb', line 32

def get_box(num)
  @points.select { |point| point.box == num }.map { |b| b.value }
end

#get_column(num) ⇒ Object



40
41
42
# File 'lib/sudoku_solver/grid.rb', line 40

def get_column(num)
  @points.select { |point| point.x == num }.map { |b| b.value }
end

#get_row(num) ⇒ Object



36
37
38
# File 'lib/sudoku_solver/grid.rb', line 36

def get_row(num)
  @points.select { |point| point.y == num }.map { |b| b.value }
end

#get_values(arr) ⇒ Object



56
57
58
# File 'lib/sudoku_solver/grid.rb', line 56

def get_values(arr)
  arr.map { |b| b.value }
end

#hidden_pairsObject



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/sudoku_solver/grid.rb', line 191

def hidden_pairs
  all_naked_pairs
  
  remaining_points.each do |point|
    next if point.nums.count <= 1
    point.nums.combination(2).each do |arr|
      components.each do |symbol|
        remove = @points.select { |p| p.send(symbol) == point.send(symbol) && arr.to_set.subset?(p.nums.to_set) && p.nums.count >= 2}
        if remove.count == 2 && @points.select { |p| p.send(symbol) == point.send(symbol) && ( arr.include?(p.value)) }.count == 0
          #remove.each { |r| r.nums = arr }
          return
        end
      end 
    end
  end
end

#is_solved?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/sudoku_solver/grid.rb', line 170

def is_solved?
  @points.select{ |p| p.value == 0 }.count == 0
end

#naked_pairsObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/sudoku_solver/grid.rb', line 114

def naked_pairs
  remaining_points.each do |point|
    next if point.nums.count <= 1
    components.each do |symbol|
      possible = remaining_points.select { |p| p.subset?(point) && p != point && p.send(symbol) == point.send(symbol) && p.nums.count >= 2 }
      possible << point
      if possible.count == point.nums.count
        compare_points(possible).each do |type|
          found = remaining_points.select { |p| p.send(type) == point.send(type) && (!possible.include?(p))  }
          found.each do |f|
            f.nums = (f.nums - point.nums)
          end
        end
      end
    end
  end
end

#pinned_pointsObject



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/sudoku_solver/grid.rb', line 86

def pinned_points
  remaining_points.each do |point|
    components.each do |symbol|
      point.nums.each do |num|
        if @points.select { |p| p.include?(num) && p.send(symbol) == point.send(symbol) && p != point }.count == 0
          point.value = num
        end
      end
    end
  end 
end

#pointing_pairsObject



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/sudoku_solver/grid.rb', line 132

def pointing_pairs
  all_naked_pairs
  remaining_points.each do |point|
    (1..9).each do |num|
      [:x, :y].each do |symbol|
        possible = @points.select { |p| p.send(symbol) == point.send(symbol) && p.box == point.box && p.include?(num) }
        if possible.count >= 2
          if @points.select { |p| p.box == point.box && (!possible.include?(p)) && p.include?(num) }.count == 0
            remove = remaining_points.select { |p| p.box != point.box && p.send(symbol) == point.send(symbol) && p.include?(num) }
            remove.each do |r|
              r.nums = (r.nums - [num])
            end
          end
        end
      end
    end
  end
end


26
27
28
29
30
# File 'lib/sudoku_solver/grid.rb', line 26

def print_values
  a = @points.map { |p| p.value}.join
  puts a 
  a
end


19
20
21
22
23
24
# File 'lib/sudoku_solver/grid.rb', line 19

def print_values_formatted
  puts "SOLUTION"
  @points.each_slice(9) do |s|
    puts s.map{ |p| p.value}.join
  end
end

#remaining_pointsObject



78
79
80
# File 'lib/sudoku_solver/grid.rb', line 78

def remaining_points
  @points.select { |p| p.value == 0 }
end

#solveObject



98
99
100
101
102
103
104
105
106
# File 'lib/sudoku_solver/grid.rb', line 98

def solve
  while !is_solved?
    all_naked_pairs
    hidden_pairs
    pointing_pairs
    box_line_reduction
    x_wing
  end
end

#update_pointsObject



60
61
62
63
64
65
66
67
68
69
# File 'lib/sudoku_solver/grid.rb', line 60

def update_points 
  @points.select { |po| po.value == 0 }.each do |poi|
    find_diff(poi)
  end
  (0..8).each do |num|
    [:box, :x, :y].each do |fields|
      yield @points.select { |p| p.send(fields) == num }
    end
  end
end

#x_wingObject



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/sudoku_solver/grid.rb', line 212

def x_wing
  box_line_reduction
  remaining_points.each do |point|
    point.nums.each do |num|
      [:x, :y].each do |symbol|
        arr = @points.select{ |p| p.nums.include?(num) && p.send(flip(symbol)) == point.send(flip(symbol)) && p.value == 0  }
        if arr.count == 2 && @points.select { |p| p.value == num && p.send(flip(symbol)) == point.send(flip(symbol)) }.count == 0
          last = @points.select { |p| p.nums.include?(num) &&
                                  arr.map{ |a| a.send(symbol) }.include?(p.send(symbol)) &&
                                  (!arr.include?(p)) &&
                                  p.value == 0 && check_row(p.y,p,num,symbol) }
          if last.all? { |x| x.send(flip(symbol)) == last.first.send(flip(symbol)) } &&
             last.count == 2 && 
             @points.select { |p| p.value == num && p.send(flip(symbol)) == last.first.send(flip(symbol)) }.count == 0
               final = arr + last 
               places = final.map { |m| m.send(symbol) }.uniq
               remaining_points.select { |p| places.include?(p.send(symbol)) && (!final.include?(p)) }.each do |poi|
               poi.nums = poi.nums - [num]
            end
          end
        end
      end
    end 
  end
  
end