class Grid

Attributes

points[RW]
remaining_nums[RW]

Public Class Methods

new(txt_file) click to toggle source
# 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

Public Instance Methods

all_naked_pairs() click to toggle source
# File lib/sudoku_solver/grid.rb, line 108
def all_naked_pairs
  fill_in
  pinned_points
  naked_pairs
end
box_count(box, num) click to toggle source
# 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_reduction() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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
components() click to toggle source
# File lib/sudoku_solver/grid.rb, line 82
def components
  [:x, :y, :box]
end
fill_in() click to toggle source
# File lib/sudoku_solver/grid.rb, line 71
def fill_in
  remaining_points.each do |p|
    find_diff(p)
  end
end
fill_row(num) click to toggle source
# File lib/sudoku_solver/grid.rb, line 44
def fill_row(num)
  @points.select { |point| point.x == num  }
end
find_diff(point) click to toggle source
# 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_points() click to toggle source
# File lib/sudoku_solver/grid.rb, line 52
def flat_points
  @points.select { |p| p.value == 0 }
end
flip(n) click to toggle source
# File lib/sudoku_solver/grid.rb, line 244
def flip(n)
  if n == :y
    :x
  else 
    :y
  end
end
get_box(num) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/sudoku_solver/grid.rb, line 56
def get_values(arr)
  arr.map { |b| b.value }
end
hidden_pairs() click to toggle source
# 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?() click to toggle source
# File lib/sudoku_solver/grid.rb, line 170
def is_solved?
  @points.select{ |p| p.value == 0 }.count == 0
end
naked_pairs() click to toggle source
# 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_points() click to toggle source
# 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_pairs() click to toggle source
# 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
print_values() click to toggle source
print_values_formatted() click to toggle source
remaining_points() click to toggle source
# File lib/sudoku_solver/grid.rb, line 78
def remaining_points
  @points.select { |p| p.value == 0 }
end
solve() click to toggle source
# 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_points() { |select { |p| send== num }| ... } click to toggle source
# 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_wing() click to toggle source
# 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