Guest User

Untitled

a guest
Oct 12th, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.95 KB | None | 0 0
  1. #
  2. # This module defines a Sudoku::Puzzle class to represent a 9x9
  3. # Sudoku puzzle and also defines exception classes raised for
  4. # invalid input and over-constrained puzzles. This module also defines
  5. # the method Sudoku.solve to solve a puzzle. The solve method uses
  6. # the Sudoku.scan method, which is also defined here.
  7. #
  8. # Use this module to solve Sudoku puzzles with code like this:
  9. #
  10. # require 'sudoku'
  11. # puts Sudoku.solve(Sudoku::Puzzle.new(ARGF.readlines))
  12. #
  13. module Sudoku
  14. #
  15. # The Sudoku::Puzzle class represents the state of a 9x9 Sudoku puzzle.
  16. #
  17. # Some definitions and terminology used in this implementation:
  18. #
  19. # - Each element of a puzzle is called a "cell".
  20. # - Rows and columns are numbered from 0 to 8, and the coordinates [0,0]
  21. # refer to the cell in the upper-left corner of the puzzle.
  22. # - The nine 3x3 subgrids are known as "boxes" and are also numbered from
  23. # 0 to 8, ordered from left to right and top to bottom. The box in
  24. # the upper-left is box 0. The box in the upper-right is box 2. The
  25. # box in the middle is box 4. The box in the lower-right is box 8.
  26. #
  27. # Create a new puzzle with Sudoku::Puzzle.new, specifying the initial
  28. # state as a string or as an array of strings. The string(s) should use
  29. # the characters 1 through 9 for the given values, and '.' for cells
  30. # whose value is unspecified. Whitespace in the input is ignored.
  31. #
  32. # Read and write access to individual cells of the puzzle is through the
  33. # [] and []= operators, which expect two-dimensional [row,column] indexing.
  34. # These methods use numbers (not characters) 0 to 9 for cell contents.
  35. # 0 represents an unknown value.
  36. #
  37. # The has_duplicates? predicate returns true if the puzzle is invalid
  38. # because any row, column, or box includes the same digit twice.
  39. #
  40. # The each_unknown method is an iterator that loops through the cells of
  41. # the puzzle and invokes the associated block once for each cell whose
  42. # value is unknown.
  43. #
  44. # The possible method returns an array of integers in the range 1..9.
  45. # The elements of the array are the only values allowed in the specified
  46. # cell. If this array is empty, then the puzzle is over-specified and
  47. # cannot be solved. If the array has only one element, then that element
  48. # must be the value for that cell of the puzzle.
  49. #
  50. class Puzzle
  51. # These constants are used for translating between the external
  52. # string representation of a puzzle and the internal representation.
  53. ASCII = ".123456789"
  54. BIN = "\000\001\002\003\004\005\006\007\010\011"
  55. # This is the initialization method for the class. It is automatically
  56. # invoked on new Puzzle instances created with Puzzle.new. Pass the input
  57. # puzzle as an array of lines or as a single string. Use ASCII digits 1
  58. # to 9 and use the '.' character for unknown cells. Whitespace,
  59. # including newlines, will be stripped.
  60. def initialize(lines)
  61. if (lines.respond_to? :join) # If argument looks like an array of lines
  62. s = lines.join # Then join them into a single string
  63. else # Otherwise, assume we have a string
  64. s = lines.dup # And make a private copy of it
  65. end
  66. # Remove whitespace (including newlines) from the data
  67. # The '!' in gsub! indicates that this is a mutator method that
  68. # alters the string directly rather than making a copy.
  69. s.gsub!(/\s/, "") # /\s/ is a Regexp that matches any whitespace
  70. # Raise an exception if the input is the wrong size.
  71. # Note that we use unless instead of if, and use it in modifier form.
  72. raise Invalid, "Grid is the wrong size" unless s.size == 81
  73. # Check for invalid characters, and save the location of the first.
  74. # Note that we assign and test the value assigned at the same time.
  75. if i = s.index(/[^123456789\.]/)
  76. # Include the invalid character in the error message.
  77. # Note the Ruby expression inside #{} in string literal.
  78. raise Invalid, "Illegal character #{s[i,1]} in puzzle"
  79. end
  80. # The following two lines convert our string of ASCII characters
  81. # to an array of integers, using two powerful String methods.
  82. # The resulting array is stored in the instance variable @grid
  83. # The number 0 is used to represent an unknown value.
  84. s.tr!(ASCII, BIN) # Translate ASCII characters into bytes
  85. @grid = s.unpack('c*') # Now unpack the bytes into an array of numbers
  86. # Make sure that the rows, columns, and boxes have no duplicates.
  87. raise Invalid, "Initial puzzle has duplicates" if has_duplicates?
  88. end
  89. # Return the state of the puzzle as a string of 9 lines with 9
  90. # characters (plus newline) each.
  91. def to_s
  92. # This method is implemented with a single line of Ruby magic that
  93. # reverses the steps in the initialize() method. Writing dense code
  94. # like this is probably not good coding style, but it demonstrates
  95. # the power and expressiveness of the language.
  96. #
  97. # Broken down, the line below works like this:
  98. # (0..8).collect invokes the code in curly braces 9 times--once
  99. # for each row--and collects the return value of that code into an
  100. # array. The code in curly braces takes a subarray of the grid
  101. # representing a single row and packs its numbers into a string.
  102. # The join() method joins the elements of the array into a single
  103. # string with newlines between them. Finally, the tr() method
  104. # translates the binary string representation into ASCII digits.
  105. (0..8).collect{|r| @grid[r*9,9].pack('c9')}.join("\n").tr(BIN,ASCII)
  106. end
  107. # Return a duplicate of this Puzzle object.
  108. # This method overrides Object.dup to copy the @grid array.
  109. def dup
  110. copy = super # Make a shallow copy by calling Object.dup
  111. @grid = @grid.dup # Make a new copy of the internal data
  112. copy # Return the copied object
  113. end
  114. # We override the array access operator to allow access to the
  115. # individual cells of a puzzle. Puzzles are two-dimensional,
  116. # and must be indexed with row and column coordinates.
  117. def [](row, col)
  118. # Convert two-dimensional (row,col) coordinates into a one-dimensional
  119. # array index and get and return the cell value at that index
  120. @grid[row*9 + col]
  121. end
  122. # This method allows the array access operator to be used on the
  123. # lefthand side of an assignment operation. It sets the value of
  124. # the cell at (row, col) to newvalue.
  125. def []=(row, col, newvalue)
  126. # Raise an exception unless the new value is in the range 0 to 9.
  127. unless (0..9).include? newvalue
  128. raise Invalid, "illegal cell value"
  129. end
  130. # Set the appropriate element of the internal array to the value.
  131. @grid[row*9 + col] = newvalue
  132. end
  133. # This array maps from one-dimensional grid index to box number.
  134. # It is used in the method below. The name BoxOfIndex begins with a
  135. # capital letter, so this is a constant. Also, the array has been
  136. # frozen, so it cannot be modified.
  137. BoxOfIndex = [
  138. 0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,
  139. 3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
  140. 6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8
  141. ].freeze
  142. # This method defines a custom looping construct (an "iterator") for
  143. # Sudoku puzzles. For each cell whose value is unknown, this method
  144. # passes ("yields") the row number, column number, and box number to the
  145. # block associated with this iterator.
  146. def each_unknown
  147. 0.upto 8 do |row| # For each row
  148. 0.upto 8 do |col| # For each column
  149. index = row*9+col # Cell index for (row,col)
  150. next if @grid[index] != 0 # Move on if we know the cell's value
  151. box = BoxOfIndex[index] # Figure out the box for this cell
  152. def has_duplicates?
  153. # uniq! returns nil if all the elements in an array are unique.
  154. # So if uniq! returns something then the board has duplicates.
  155. 0.upto(8) {|row| return true if rowdigits(row).uniq! }
  156. 0.upto(8) {|col| return true if coldigits(col).uniq! }
  157. 0.upto(8) {|box| return true if boxdigits(box).uniq! }
  158. false # If all the tests have passed, then the board has no duplicates
  159. end
  160. # This array holds a set of all Sudoku digits. Used below.
  161. AllDigits = [1, 2, 3, 4, 5, 6, 7, 8, 9].freeze
  162. # Return an array of all values that could be placed in the cell
  163. # at (row,col) without creating a duplicate in the row, column, or box.
  164. # Note that the + operator on arrays does concatenation but that the -
  165. # operator performs a set difference operation.
  166. def possible(row, col, box)
  167. AllDigits - (rowdigits(row) + coldigits(col) + boxdigits(box))
  168. end
  169. private # All methods after this line are private to the class
  170. # Return an array of all known values in the specified row.
  171. def rowdigits(row)
  172. # Extract the subarray that represents the row and remove all zeros.
  173. # Array subtraction is set difference, with duplicate removal.
  174. @grid[row*9,9] - [0]
  175. end
  176. # Return an array of all known values in the specified column.
  177. def coldigits(col)
  178. result = [] # Start with an empty array
  179. col.step(80, 9) {|i| # Loop from col by nines up to 80
  180. v = @grid[i] # Get value of cell at that index
  181. result << v if (v != 0) # Add it to the array if non-zero
  182. }
  183. result # Return the array
  184. end
  185. # Map box number to the index of the upper-left corner of the box.
  186. BoxToIndex = [0, 3, 6, 27, 30, 33, 54, 57, 60].freeze
  187. # Return an array of all the known values in the specified box.
  188. def boxdigits(b)
  189. # Convert box number to index of upper-left corner of the box.
  190. i = BoxToIndex[b]
  191. # Return an array of values, with 0 elements removed.
  192. [
  193. @grid[i], @grid[i+1], @grid[i+2],
  194. @grid[i+9], @grid[i+10], @grid[i+11],
  195. @grid[i+18], @grid[i+19], @grid[i+20]
  196. ] - [0]
  197. end
  198. end # This is the end of the Puzzle class
  199. # An exception of this class indicates invalid input,
  200. class Invalid < StandardError
  201. end
  202. # An exception of this class indicates that a puzzle is over-constrained
  203. # and that no solution is possible.
  204. class Impossible < StandardError
  205. end
  206. #
  207. # This method scans a Puzzle, looking for unknown cells that have only
  208. # a single possible value. If it finds any, it sets their value. Since
  209. # setting a cell alters the possible values for other cells, it
  210. # continues scanning until it has scanned the entire puzzle without
  211. # finding any cells whose value it can set.
  212. #
  213. # This method returns three values. If it solves the puzzle, all three
  214. # values are nil. Otherwise, the first two values returned are the row and
  215. # column of a cell whose value is still unknown. The third value is the
  216. # set of values possible at that row and column. This is a minimal set of
  217. # possible values: there is no unknown cell in the puzzle that has fewer
  218. # possible values. This complex return value enables a useful heuristic
  219. # in the solve() method: that method can guess at values for cells where
  220. # the guess is most likely to be correct.
  221. #
  222. # This method raises Impossible if it finds a cell for which there are
  223. # no possible values. This can happen if the puzzle is over-constrained,
  224. # or if the solve() method below has made an incorrect guess.
  225. #
  226. # This method mutates the specified Puzzle object in place.
  227. # If has_duplicates? is false on entry, then it will be false on exit.
  228. #
  229. def Sudoku.scan(puzzle)
  230. unchanged = false # This is our loop variable
  231. # Loop until we've scanned the whole board without making a change.
  232. until unchanged
  233. unchanged = true # Assume no cells will be changed this time
  234. rmin,cmin,pmin = nil # Track cell with minimal possible set
  235. min = 10 # More than the maximal number of possibilities
  236. # Loop through cells whose value is unknown.
  237. puzzle.each_unknown do |row, col, box|
  238. # Find the set of values that could go in this cell
  239. p = puzzle.possible(row, col, box)
  240. # Branch based on the size of the set p.
  241. # We care about 3 cases: p.size==0, p.size==1, and p.size > 1.
  242. case p.size
  243. when 0 # No possible values means the puzzle is over-constrained
  244. raise Impossible
  245. when 1 # We've found a unique value, so set it in the grid
  246. puzzle[row,col] = p[0] # Set that position on the grid to the value
  247. unchanged = false # Note that we've made a change
  248. else # For any other number of possibilities
  249. # Keep track of the smallest set of possibilities.
  250. # But don't bother if we're going to repeat this loop.
  251. if unchanged && p.size < min
  252. min = p.size # Current smallest size
  253. rmin, cmin, pmin = row, col, p # Note parallel assignment
  254. end
  255. end
  256. end
  257. end
  258. # Return the cell with the minimal set of possibilities.
  259. # Note multiple return values.
  260. return rmin, cmin, pmin
  261. end
  262. # Solve a Sudoku puzzle using simple logic, if possible, but fall back
  263. # on brute-force when necessary. This is a recursive method. It either
  264. # returns a solution or raises an exception. The solution is returned
  265. # as a new Puzzle object with no unknown cells. This method does not
  266. # modify the Puzzle it is passed. Note that this method cannot detect
  267. # an under-constrained puzzle.
  268. def Sudoku.solve(puzzle)
  269. # Make a private copy of the puzzle that we can modify.
  270. puzzle = puzzle.dup
  271. # Use logic to fill in as much of the puzzle as we can.
  272. # This method mutates the puzzle we give it, but always leaves it valid.
  273. # It returns a row, a column, and set of possible values at that cell.
  274. # Note parallel assignment of these return values to three variables.
  275. r,c,p = scan(puzzle)
  276. # If we solved it with logic, return the solved puzzle.
  277. return puzzle if r == nil
  278. # Otherwise, try each of the values in p for cell [r,c].
  279. # Since we're picking from a set of possible values, the guess leaves
  280. # the puzzle in a valid state. The guess will either lead to a solution
  281. # or to an impossible puzzle. We'll know we have an impossible
  282. # puzzle if a recursive call to scan throws an exception. If this happens
  283. # we need to try another guess, or re-raise an exception if we've tried
  284. # all the options we've got.
  285. p.each do |guess| # For each value in the set of possible values
  286. puzzle[r,c] = guess # Guess the value
  287. begin
  288. # Now try (recursively) to solve the modified puzzle.
  289. # This recursive invocation will call scan() again to apply logic
  290. # to the modified board, and will then guess another cell if needed.
  291. # Remember that solve() will either return a valid solution or
  292. # raise an exception.
  293. return solve(puzzle) # If it returns, we just return the solution
  294. rescue Impossible
  295. next # If it raises an exception, try the next guess
  296. end
  297. end
  298. # If we get here, then none of our guesses worked out
  299. # so we must have guessed wrong sometime earlier.
  300. raise Impossible
  301. end
  302. end
Add Comment
Please, Sign In to add comment