$sudoku = [] $color = [] $sectors = [[0,0], [1,0], [2,0], [0,1], [1,1], [2,1], [0,2], [1,2], [2,2]] 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 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,num) positions.map{ |p| sget(sid,p[0],p[1]) }.uniq 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)) + [[0,y],[1,y],[2,y],[3,y],[4,y],[5,y],[6,y],[7,y],[8,y],[9,y], [x,0],[x,1],[x,2],[x,3],[x,4],[x,5],[x,6],[x,7],[x,8],[x,9]] $sudoku[sid][y][x] = $sudoku[sid][y][x] - find_num(sid,related,num) end end end end def srestr(sid,x,y,num) # restricts: num can't be on this field return if sget(sid,x,y).is_a? Numeric sset_array(sid,x,y, sget(sid,x,y).reject{ |c| c == num } ) end def sset_scalar(sid,x,y,num) if !$sudoku[sid][y][x].is_a? Numeric and !$sudoku[sid][y][x].include?(num) puts "WARNING: sset called with invalid num #{num}" return end # puts "LL #{x} #{y} #{num}" $sudoku[sid][y][x] = num secmem = secgroup(sec_id(x,y)) 9.times do |n| srestr(sid,n,y,num); srestr(sid,x,n,num) srestr(sid,secmem[n][0],secmem[n][1],num) end 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 "LL #{x} #{y} #{num}" $sudoku[zsid][zy][zx] = num end end end end end end def sset_array(sid,x,y,num) # puts "LL #{x} #{y} #{num}" $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 "LL #{x} #{y} #{num & $sudoku[zsid][zy][zx]}" $sudoku[zsid][zy][zx] = num & $sudoku[zsid][zy][zx] end end 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 sset_scalar(sid,x,y,num) else sset_array(sid,x,y,num) end $sudoku.length.times do |zsid| 9.times do |zx| 9.times do |zy| if $sudoku[zsid][zy][zx].is_a? Array and $sudoku[zsid][zy][zx].length == 1 sset(zsid,zx,zy,sget(zsid,zx,zy)) end end end end end $pass_count = 0 def pass(sid) $pass_count = $pass_count + 1 puts "===== PASS #{$pass_count}, SUDOKU #{sid} =====" # check rows for unique numbers 9.times do |num| 9.times do |y| found = nil 9.times do |x| if !sget(sid,x,y).is_a? Numeric and sget(sid,x,y).include? num found = true if found found = x if !found end end sset(sid,found,y,num) if found.is_a? Numeric end end # check columns for unique numbers 9.times do |num| 9.times do |x| found = nil 9.times do |y| if !sget(sid,x,y).is_a? Numeric and sget(sid,x,y).include? num found = true if found found = y if !found end end sset(sid,x,found,num) if found.is_a? Numeric end end # check sectors for unique numbers 9.times do |num| 9.times do |sector| secmem = secgroup(sector) found = nil 9.times do |pos| x = secmem[pos][0] y = secmem[pos][1] if !sget(sid,x,y).is_a? Numeric and sget(sid,x,y).include? num found = true if found found = [x,y] if !found end end sset(sid,found[0],found[1],num) if found.is_a? Array end end 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 9.times do |y| 9.times do |x| sset(sid,x,y,sget(sid,x,y)) end end end def loadf(filename = "sudoku1.txt") File.open(filename) do |f| f.gets.to_i.times { load f } end end