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.



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

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
  
  @points.select { |po| po.value == 0 }.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.



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

def points
  @points
end

#remaining_numsObject

Returns the value of attribute remaining_nums.



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

def remaining_nums
  @remaining_nums
end

Instance Method Details

#all_naked_pairsObject



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

def all_naked_pairs
  fill_in
  pinned_points
  naked_pairs
end

#box_count(box, num) ⇒ Object



211
212
213
# File 'lib/sudoku_solver/grid.rb', line 211

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

#box_line_reductionObject



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

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



237
238
239
240
# File 'lib/sudoku_solver/grid.rb', line 237

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



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

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



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

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

#fill_inObject



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

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

#fill_row(num) ⇒ Object



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

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

#find_diff(point) ⇒ Object



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

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

#flat_pointsObject



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

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

#flip(n) ⇒ Object



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

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

#get_box(num) ⇒ Object



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

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

#get_column(num) ⇒ Object



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

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

#get_row(num) ⇒ Object



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

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

#get_values(arr) ⇒ Object



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

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

#hidden_pairsObject



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

def hidden_pairs
  all_naked_pairs
#   @points.select { |p| p.x == 6  &&  p.y == 4  }.first.nums =  @points.select { |p| p.x == 6  &&  p.y == 4  }.first.nums - [1,5]
#   @points.select { |p| p.x == 6  &&  p.y == 6  }.first.nums =  @points.select { |p| p.x == 6  &&  p.y == 6  }.first.nums - [3,6]
  
  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)


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

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

#naked_pairsObject



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

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



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

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



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

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


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

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


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

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

#remaining_pointsObject



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

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

#solveObject



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

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

#update_pointsObject



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

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



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

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