IceDragon200

Sudoku Solver

Sep 28th, 2012
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 4.45 KB | None | 0 0
  1. =begin
  2.  
  3.   ruby/sudoku_solver.rb
  4.   by IceDragon
  5.   at 28/09/2012
  6.  
  7.   :x The most inefficient solver known to man
  8.  
  9. =end
  10.  
  11. module ArrayTools
  12.  
  13.   def self.rotate(array, n=1)
  14.     array.concat(array.slice!(0, n))
  15.   end
  16.  
  17. end
  18.  
  19. # // Main module
  20. module Sudoku
  21.  
  22.   # // A constant is fitting cause this stuff never changes :x
  23.   XSIZE = 9
  24.   YSIZE = 9
  25.  
  26.   XBLOCK_SIZE = 3
  27.   YBLOCK_SIZE = 3
  28.  
  29.   private
  30.   # // Bleh, lazy method for making multi_dimensional arrays
  31.   # // Initializes the array with elements of 0
  32.   # // return Array<Array<int>>
  33.   # // Array[y][x] => int
  34.   def self.multi_dim_array2(ysize, xsize, populate=0)
  35.     Array.new(ysize) do Array.new(xsize, populate) end
  36.   end
  37.  
  38.   def self.index_to_xy(index, xsize=XSIZE)
  39.     x = index % xsize
  40.     y = index/xsize
  41.     return x, y
  42.   end
  43.  
  44.   def self.obj_in_column?(array, obj, x)
  45.     for y in 0...YSIZE
  46.       if array[y][x] == obj
  47.         #puts "#{obj} is present in column #{x}"
  48.         return true
  49.       end
  50.     end
  51.     #puts "#{obj} is not present in column #{x}"
  52.     return false
  53.   end
  54.  
  55.   def self.obj_in_row?(array, obj, y)
  56.     if array[y].include?(obj)
  57.       #puts "#{obj} is present in row #{y}"  
  58.       return true
  59.     else
  60.       #puts "#{obj} is not present in row #{y}"
  61.       return false
  62.     end
  63.   end
  64.  
  65.   def self.obj_in_block?(array, obj, xp, yp)
  66.     block_x = xp / XBLOCK_SIZE
  67.     block_y = yp / YBLOCK_SIZE
  68.     bxs = block_x * XBLOCK_SIZE
  69.     bys = block_y * YBLOCK_SIZE
  70.     for y in bys...(bys + YBLOCK_SIZE)
  71.       row = array[y]
  72.       for x in bxs...(bxs + XBLOCK_SIZE)
  73.         if row[x] == obj
  74.           #puts "#{obj} is present in #{block_x}, #{block_y}"
  75.           return true
  76.         end
  77.       end
  78.     end
  79.     #puts "#{obj} is not present in #{block_x}, #{block_y}"
  80.     return false
  81.   end
  82.  
  83.   def self.obj_valid_pos?(array, obj, x, y)
  84.     return false if obj_in_column?(array, obj, x)
  85.     return false if obj_in_row?(array, obj, y)
  86.     return false if obj_in_block?(array, obj, x, y)
  87.     return true
  88.   end
  89.  
  90.   public
  91.  
  92. =begin
  93.  
  94.   Sudoku is a 9x9 grid
  95.  
  96. =end
  97.   def self.generate()
  98.     xsize, ysize = XSIZE, YSIZE
  99.     begin
  100.       res = nil
  101.       while !res
  102.         result   = multi_dim_array2(ysize, xsize, " ")
  103.         lead_row = (1..XSIZE).to_a.sort_by do rand() end
  104.         result[0].replace(lead_row)
  105.         res = solve_table(result)
  106.       end
  107.       # // Black out at random
  108.       for y in 0...ysize
  109.         for x in 0...xsize
  110.           next unless rand(2) == 0
  111.           res[y][x] = " "
  112.         end
  113.       end
  114.       result = res
  115.     end
  116.     result
  117.   end
  118.  
  119.   def self.solve_table(result)
  120.     for y in 0...YSIZE
  121.       inds = ((1..YSIZE).to_a - result[y]).sort_by do rand() end
  122.       x = 0
  123.       while x < XSIZE
  124.         #sleep(0.1)
  125.         #system('cls')
  126.         #puts "Generating Row: #{y}"
  127.         #print_multi_dim_array2(result, YSIZE)
  128.         #puts "Row: #{result[y].join('|')}"
  129.         id = inds[0]
  130.         if result[y][x] != " "
  131.           x += 1  
  132.         elsif obj_valid_pos?(result, id, x, y) and result[y][x] == " "
  133.           inds.delete(id)
  134.           result[y][x] = id
  135.           x += 1
  136.         elsif !inds.empty? and !inds.any? do |a| obj_valid_pos?(result, a, x, y) end
  137.           return nil
  138.         else
  139.           ArrayTools.rotate(inds, 1)
  140.         end
  141.       end
  142.     end
  143.     return result
  144.   end
  145.  
  146.   def self.solve(sudoku_array)
  147.     res = nil
  148.     while !res
  149.       result = Marshal.load(Marshal.dump(sudoku_array))
  150.       res = solve_table(result)
  151.     end
  152.     return res
  153.   end
  154.  
  155. end
  156.  
  157. # // Method used for printing multi dimensional arrays
  158. def print_multi_dim_array2(array, ysize, joint=" | ")
  159.   # // We start from y not x
  160.   # // since we write line by line, and not column by column :)
  161.   for y in 0...ysize
  162.     row = array[y]
  163.     print(" #{Array.new(row.size, "-").join(joint)}\n")
  164.     print(" #{row.join(joint)}\n")
  165.   end
  166. end
  167.  
  168. # // C habits die hard
  169. def main()
  170.   sudoku_array = Sudoku.generate()
  171.   puts "To solve:"
  172.   print_multi_dim_array2(sudoku_array, Sudoku::YSIZE)
  173.   puts "Solving..."
  174.   time_then = Time.now
  175.   result = Sudoku.solve(sudoku_array)
  176.   time_elapsed = Time.now - time_then
  177.   puts "Solved in: #{time_elapsed.round(0)}sec(s)"
  178.   print_multi_dim_array2(result, Sudoku::YSIZE)
  179.   # // C habits really die hard :x
  180.   return 0;
  181. end
  182.  
  183. # // My Usual ruby block :)
  184. begin
  185.   main()
  186. rescue(Exception) => ex
  187.   # // Output to console
  188.   p ex
  189.   puts ex.backtrace
  190.   #raise ex # // Only if your using RM :)
  191. end
Advertisement
Add Comment
Please, Sign In to add comment