$sudoku = [] $color = [] $sectors = [[0,0], [1,0], [2,0], [0,1], [1,1], [2,1], [0,2], [1,2], [2,2]] def colgroup(x) [[x,0],[x,1],[x,2],[x,3],[x,4],[x,5],[x,6],[x,7],[x,8]] end def rowgroup(y) [[0,y],[1,y],[2,y],[3,y],[4,y],[5,y],[6,y],[7,y],[8,y]] end def secgroup(id) x = 3 * (id % 3) y = 3 * (id / 3) $sectors.map { |n| [n[0]+x, n[1]+y] } end def sec_id(x,y) $sectors.index([x / 3, y / 3]) end def sdump(sid) 9.times { |y| p $sudoku[sid][y] } end def sprint(sid) 9.times do |y| 9.times { |x| print(sget(sid,x,y).is_a?(Numeric) ? sget(sid,x,y).to_s : " ") } print "\n" end end def sget(sid,x,y) $sudoku[sid][y][x] end def find_numbers(sid,positions) positions.map{ |p| sget(sid,p[0],p[1]) }.uniq end def find_possibilities(sid, positions, num) return [] if positions.find{ |p| x = sget(sid,p[0],p[1]); x == num } positions.find_all{ |p| x = sget(sid,p[0],p[1]); x.is_a? Array and x.include? num } end def recalculate(sid) 9.times do |x| 9.times do |y| $sudoku[sid][y][x] = [1,2,3,4,5,6,7,8,9] if !$sudoku[sid][y][x].is_a? Numeric end end 9.times do |y| 9.times do |x| if !$sudoku[sid][y][x].is_a? Numeric related = secgroup(sec_id(x,y)) + colgroup(x) + rowgroup(y) $sudoku[sid][y][x] = $sudoku[sid][y][x] - find_numbers(sid,related) end if $sudoku[sid][y][x].is_a? Array and $sudoku[sid][y][x].length == 1 puts "#{x} #{y} #{$sudoku[sid][y][x][0]}" $sudoku[sid][y][x] = $sudoku[sid][y][x][0] end end end end def sset(sid,x,y,num) puts "#{x} #{y} #{num}" if num.is_a? Numeric or num.length < 9 num = num[0] if !num.is_a? Numeric and num.length == 1 if num.is_a? Numeric and !$sudoku[sid][y][x].is_a? Numeric and !$sudoku[sid][y][x].include?(num) puts "WARNING: sset called with invalid num #{num}" return end $sudoku[sid][y][x] = num if $color[sid][y][x] $sudoku.length.times do |zsid| 9.times do |zx| 9.times do |zy| if $color[sid][y][x] == $color[zsid][zy][zx] puts "#{zsid}: #{zx} #{zy} #{num}" if num.is_a? Numeric $sudoku[zsid][zy][zx] = (num.is_a?(Numeric) ? num : num & $sudoku[zsid][zy][zx]) end end end end end end $pass_count = 0 def pass(sid) $pass_count = $pass_count + 1 puts "===== PASS #{$pass_count}, SUDOKU #{sid} =====" 9.times do |num| 9.times do |gid| # check rows for unique numbers group = rowgroup(gid) choices = find_possibilities(sid, group, num) sset(sid, choices[0][0], choices[0][1], num) if choices.length == 1 # check columns for unique numbers group = colgroup(gid) choices = find_possibilities(sid, group, num) sset(sid, choices[0][0], choices[0][1], num) if choices.length == 1 # check sectors for unique numbers group = secgroup(gid) choices = find_possibilities(sid, group, num) sset(sid, choices[0][0], choices[0][1], num) if choices.length == 1 end end recalculate sid end def pass_all $sudoku.length.times { |i| pass i } end def create_new Array.new(9).map{Array.new(9).map{[1,2,3,4,5,6,7,8,9]}} end def empty_color Array.new(9).map{Array.new(9)} end def load(file) sid = $sudoku.length puts "LOADING SUDOKU #{sid}" $sudoku << create_new $color << empty_color file.gets # separator 9.times do |y| line = file.gets.chomp 9.times do |x| policko = line[2*x,1] $color[sid][y][x] = policko if policko != " " policko = line[2*x+1,1] if policko != " " and policko.to_i == 0 puts "ERROR: invalid input syntax at char #{2*x+2} line #{y+1} of sudoku #{sid+1}" exit end $sudoku[sid][y][x] = policko.to_i if policko != " " end end recalculate sid end def loadf(filename = "sudoku1.txt") File.open(filename) do |f| f.gets.to_i.times { load f } end end