Advertisement
Guest User

Untitled

a guest
Jul 23rd, 2016
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.86 KB | None | 0 0
  1. /*
  2. Copyright (c) 2015 Kristopher Johnson
  3.  
  4. Permission is hereby granted, free of charge, to any person obtaining
  5. a copy of this software and associated documentation files (the
  6. "Software"), to deal in the Software without restriction, including
  7. without limitation the rights to use, copy, modify, merge, publish,
  8. distribute, sublicense, and/or sell copies of the Software, and to
  9. permit persons to whom the Software is furnished to do so, subject to
  10. the following conditions:
  11.  
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14.  
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23.  
  24. /// A Mark is an value in the range 1...9
  25. ///
  26. /// An assertion failure will be triggered if an attempt is made
  27. /// to create a mark with a value outside the valid range. If
  28. /// assertions are disabled, then any invalid values will be treated
  29. /// as the value 1.
  30. public struct Mark {
  31. public let value: Int
  32.  
  33. public init(_ value: Int) {
  34. assert(1 <= value && value <= 9, "only values 1...9 are valid for a mark")
  35.  
  36. switch value {
  37. case 1...9: self.value = value
  38. default: self.value = 1
  39. }
  40. }
  41. }
  42.  
  43. /// A Sudoku square is empty or has a mark with value 1...9.
  44. public enum Square: IntegerLiteralConvertible {
  45. case Empty
  46. case Marked(Mark)
  47.  
  48. /// Initialize a square value from an integer literal
  49. ///
  50. /// Any value in the range 1...9 will be treated as a mark.
  51. /// Any other value will result in an empty square.
  52. public init(integerLiteral value: IntegerLiteralType) {
  53. switch value {
  54. case 1...9: self = .Marked(Mark(value))
  55. default: self = .Empty
  56. }
  57. }
  58.  
  59. var isEmpty: Bool {
  60. switch self {
  61. case .Empty: return true
  62. case .Marked(_): return false
  63. }
  64. }
  65.  
  66. func isMarkedWithValue(value: Int) -> Bool {
  67. switch self {
  68. case .Empty: return false
  69. case .Marked(let mark): return mark.value == value
  70. }
  71. }
  72. }
  73.  
  74. // A Sudoku puzzle is a 9x9 matrix of squares
  75. public typealias Sudoku = [[Square]]
  76.  
  77. /// Find a solution for a sudoku puzzle
  78. public func solveSudoku(s: Sudoku) -> Sudoku? {
  79. if let (row, col) = findEmptySquare(s) {
  80. for mark in 1...9 {
  81. if canTryMark(mark, atRow: row, column: col, inSudoku: s) {
  82. let candidate = copySudoku(s, withMark: mark, atRow: row, column: col)
  83. if let solution = solveSudoku(candidate) {
  84. return solution
  85. }
  86. }
  87. }
  88.  
  89. // No solution
  90. return nil
  91. }
  92. else {
  93. // No empty squares, so it's solved
  94. return s
  95. }
  96. }
  97.  
  98. /// Find all solutions for a sudoku puzzle, invoking a user-provided function for each solution.
  99. ///
  100. /// If the user-provided function returns false, then iteration of solutions will stop.
  101. public func findAllSolutions(s: Sudoku, processAndContinue: (Sudoku) -> Bool) {
  102. // This will be set true if processAndContinue() returns false
  103. var stop = false
  104.  
  105. // Local functions can't refer to themselves, so to let findSolutionsUntilStop()
  106. // make a recursive call to itself, we need to have another local variable that
  107. // holds a reference to it.
  108. var recursiveCall: (Sudoku) -> () = { _ in return }
  109.  
  110. // This is the same as solveSudoku(), except that it invokes processAndContinue()
  111. // when it finds a solution, and if that returns true, it keeps searching for
  112. // solutions.
  113. func findSolutionsUntilStop(s: Sudoku) {
  114. if let (row, col) = findEmptySquare(s) {
  115. for mark in 1...9 {
  116. if stop {
  117. break
  118. }
  119.  
  120. if canTryMark(mark, atRow: row, column: col, inSudoku: s) {
  121. let candidate = copySudoku(s, withMark: mark, atRow: row, column: col)
  122. recursiveCall(candidate)
  123. }
  124. }
  125. }
  126. else {
  127. // No empty squares, so this is a solution
  128. if !processAndContinue(s) {
  129. stop = true
  130. }
  131. }
  132. }
  133.  
  134. recursiveCall = findSolutionsUntilStop
  135.  
  136. findSolutionsUntilStop(s)
  137. }
  138.  
  139. /// Print a Sudoku as a 9x9 matrix
  140. ///
  141. /// Empty squares are printed as dots.
  142. public func printSudoku(s: Sudoku) {
  143. for row in s {
  144. for square in row {
  145. switch (square) {
  146. case .Empty: print(".")
  147. case .Marked(let mark): print(mark.value)
  148. }
  149. }
  150. println()
  151. }
  152. }
  153.  
  154. /// Create a copy of a Sudoku with an additional mark
  155. private func copySudoku(s: Sudoku, withMark mark: Int, atRow row: Int, column col: Int) -> Sudoku {
  156. var result = Sudoku(s)
  157.  
  158. var newRow = Array(s[row])
  159. newRow[col] = .Marked(Mark(mark))
  160. result[row] = newRow
  161.  
  162. return result
  163. }
  164.  
  165. /// Find an empty square in a Sudoku board
  166. ///
  167. /// :returns: (row, column), or nil if there are no empty squares
  168. private func findEmptySquare(s: Sudoku) -> (Int, Int)? {
  169. for row in 0..<9 { for col in 0..<9 {
  170. if s[row][col].isEmpty { return (row, col) }
  171. }}
  172. return nil
  173. }
  174.  
  175. /// Determine whether putting the specified mark at the specified square would violate uniqueness constrains
  176. private func canTryMark(mark: Int, atRow row: Int, column col: Int, inSudoku s: Sudoku) -> Bool {
  177. return !doesSudoku(s, containMark: mark, inRow: row)
  178. && !doesSudoku(s, containMark: mark, inColumn: col)
  179. && !doesSudoku(s, containMark: mark, in3x3BoxWithRow: row, column: col)
  180. }
  181.  
  182. /// Determine whether a specified mark already exists in a specified row
  183. private func doesSudoku(s: Sudoku, containMark mark: Int, inRow row: Int) -> Bool {
  184. for col in 0..<9 {
  185. if s[row][col].isMarkedWithValue(mark) { return true }
  186. }
  187. return false
  188. }
  189.  
  190. /// Determine whether a specified mark already exists in a specified column
  191. private func doesSudoku(s: Sudoku, containMark mark: Int, inColumn col: Int) -> Bool {
  192. for row in 0..<9 {
  193. if s[row][col].isMarkedWithValue(mark) { return true }
  194. }
  195. return false
  196. }
  197.  
  198. /// Determine whether a specified mark already exists in a specified 3x3 subgrid
  199. private func doesSudoku(s: Sudoku, containMark mark: Int, in3x3BoxWithRow row: Int, column col: Int) -> Bool {
  200. let boxMinRow = (row / 3) * 3
  201. let boxMaxRow = boxMinRow + 2
  202. let boxMinCol = (col / 3) * 3
  203. let boxMaxCol = boxMinCol + 2
  204.  
  205. for row in boxMinRow...boxMaxRow {
  206. for col in boxMinCol...boxMaxCol {
  207. if s[row][col].isMarkedWithValue(mark) { return true }
  208. }
  209. }
  210. return false
  211. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement