Advertisement
Guest User

Untitled

a guest
Feb 15th, 2016
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.49 KB | None | 0 0
  1. (* returns true if there is a zero in the given list *)
  2. fun zeroInList list =
  3. if length (List.filter (fn x => x = 0) list) > 0 then true else false;
  4.  
  5. (* returns true if a list of lists has no 0's (does not check for valid Sudoku board) *)
  6. fun completedBoard lists =
  7. if length (List.filter zeroInList lists) > 0 then false else true;
  8.  
  9. (* inserts an element into a list at the specified position *)
  10. fun insertAtPos [] x k = [x]
  11. | insertAtPos ls x 0 = x::ls
  12. | insertAtPos (l::ls) x k = l::(insertAtPos ls x (k - 1));
  13.  
  14. (* sums a list *)
  15. fun total [] = 0
  16. | total (x::xs) = x + (total xs);
  17.  
  18. (* calculates the triangular sum of a given number
  19. ex: triangularSum 5 = 5 + 4 + 3 + 2 + 1 = 15 *)
  20. fun triangularSum 0 = 0
  21. | triangularSum num = num + triangularSum (num - 1);
  22.  
  23. (* remove an element from a list *)
  24. fun removeElem s [] = []
  25. | removeElem s (x::xs) =
  26. if s = x then xs
  27. else x::(removeElem s xs);
  28.  
  29. (* remove an element (by index) from a list *)
  30. fun delete (_, nil) = nil
  31. | delete (0, _::xs) = xs
  32. | delete (i, x::xs) = x::delete(i-1,xs);
  33.  
  34. (* replaces a 0 in a list with the "missing number" *)
  35. fun insertNum list =
  36. if not(zeroInList list) then list
  37. else
  38. let
  39. fun insertNum' list index =
  40. if List.nth(list, index) = 0 then
  41. let
  42. fun numberMissing list = (triangularSum (length list)) - (total list);
  43. in
  44. removeElem 0 (insertAtPos list (numberMissing list) index)
  45. end
  46. else insertNum' list (index + 1)
  47. in
  48. insertNum' list 0
  49. end;
  50.  
  51.  
  52. (* fills the missing spot of a given list (used to force sudoku rows / cols / boxes *)
  53. fun fillList list =
  54. if length (List.filter (fn x => x = 0) list) = 1 then insertNum list
  55. else list;
  56.  
  57. (* returns true if there is a duplicate of any number other than zero in a given list *)
  58. fun isNonZeroDupe [] = false
  59. | isNonZeroDupe (x::xs) =
  60. (List.exists (fn y => if y = 0 then false else x = y) xs)
  61. orelse (isNonZeroDupe xs);
  62.  
  63. (* returns the index of an element in a list *)
  64. fun index (x, []) = raise Subscript
  65. | index (x, y::ys) =
  66. if x = y then 0 else 1 + index (x, ys);
  67.  
  68. fun getNth num list = List.nth(list, num);
  69.  
  70. (* converts a list of lists that represent the rows of a sudoku board into the columns *)
  71. fun rowsToCols rows =
  72. let
  73. fun rowsToCols' rows cols index =
  74. if index = (length rows) then cols
  75. else rowsToCols' rows (cols@[(map (getNth index) rows)]) (index + 1)
  76. in
  77. rowsToCols' rows [] 0
  78. end;
  79.  
  80. (* converts a list of lists that represent the rows of a sudoku board into the 3x3 boxes *)
  81. fun rowsToBoxes rows =
  82. let
  83. fun rowsToBoxes' rows boxes index =
  84. if index + 2 >= (length rows) then boxes
  85. else
  86. let
  87. val box1 = List.take(List.nth(rows, index), 3)
  88. @List.take(List.nth(rows, index + 1), 3)
  89. @List.take(List.nth(rows, index + 2), 3);
  90.  
  91. val box2 = List.drop(List.take(List.nth(rows, index), 6), 3)
  92. @List.drop(List.take(List.nth(rows, index + 1), 6), 3)
  93. @List.drop(List.take(List.nth(rows, index + 2), 6), 3);
  94.  
  95. val box3 = List.drop(List.take(List.nth(rows, index), 9), 6)
  96. @List.drop(List.take(List.nth(rows, index + 1), 9), 6)
  97. @List.drop(List.take(List.nth(rows, index + 2), 9), 6);
  98. in
  99. rowsToBoxes' rows (boxes@[box1]@[box2]@[box3]) (index + 3)
  100. end;
  101. in
  102. rowsToBoxes' rows [] 0
  103. end;
  104.  
  105. (* forces any empty spots of a given sudoku board *)
  106. fun force board =
  107. let
  108. fun forceRows board =
  109. map fillList board;
  110. fun forceCols board =
  111. rowsToCols(map fillList (rowsToCols board));
  112. fun forceBoxes board =
  113. rowsToBoxes(map fillList (rowsToBoxes board));
  114. in
  115. forceBoxes (forceCols (forceRows board))
  116. end;
  117.  
  118. (* checks if a given sudoku board is legal *)
  119. fun checkLegal board =
  120. let
  121. fun checkRows board =
  122. if length (List.filter isNonZeroDupe board) > 0 then false else true;
  123. fun checkCols board =
  124. if length (List.filter isNonZeroDupe (rowsToCols board)) > 0 then false
  125. else true;
  126. fun checkBoxes board =
  127. if length (List.filter isNonZeroDupe (rowsToBoxes board)) > 0 then false
  128. else true;
  129. in
  130. checkRows board andalso checkCols board andalso checkBoxes board
  131. end;
  132.  
  133. exception Sudoku;
  134. fun solve board =
  135. let fun solve' board k =
  136. (* k is the row we are working on, so if it's 9, we SHOULD be done *)
  137. if k = 9 then board else
  138. let
  139. (* get row k from the board *)
  140. val row = (List.nth (board, k));
  141.  
  142. fun trySpot number col =
  143. (* if number >= 10, raise an exception to backtrack *)
  144. if number > (length row) then raise Sudoku
  145. (* if col = 9, raise an exception to backtrack *)
  146. else if col = 9 then raise Sudoku
  147. (* if row[col] is not a zero, move to next col *)
  148. else if not (List.nth(row, col) = 0) then trySpot number (col + 1)
  149. (* row doesn't contain this num already *)
  150. else if length (List.filter (fn x => x = number) row) = 0 then
  151. let
  152. (* build the new row and board and check if legal (this works fine) *)
  153. val newRow = delete(col + 1, (insertAtPos row number col));
  154. val newBoard = delete(k + 1, (insertAtPos board newRow k));
  155. val isLegal = checkLegal newBoard;
  156. in
  157. (* if legal, keep solving with new board as base *)
  158. if isLegal then
  159. solve' (force newBoard) 0
  160. handle Sudoku => solve' (force board) (k + 1)
  161. (* not legal, try with next num *)
  162. else trySpot (number + 1) col
  163. end
  164. (* row already has this number, skipping *)
  165. else trySpot (number + 1) col
  166. in
  167. (* if board is complete and legal we're done *)
  168. if completedBoard board andalso checkLegal board then board
  169. (* if row has a zero then try a spot *)
  170. else if (zeroInList row) then trySpot 1 0
  171. (* otherwise move to next row *)
  172. else solve' (force board) (k + 1)
  173. end
  174. in
  175. (* initial solve *)
  176. solve' (force board) 0
  177. end;
  178.  
  179. (* test board
  180. solve by calling: solve easy; *)
  181. val easy = [
  182. [0,0,0, 2,6,0, 7,0,1],
  183. [6,8,0, 0,7,0, 0,9,0],
  184. [1,9,0, 0,0,4, 5,0,0],
  185.  
  186. [8,2,0, 1,0,0, 0,4,0],
  187. [0,0,4, 6,0,2, 9,0,0],
  188. [0,5,0, 0,0,3, 0,2,8],
  189.  
  190. [0,0,9, 3,0,0, 0,7,4],
  191. [0,4,0, 0,5,0, 0,3,6],
  192. [7,0,3, 0,1,8, 0,0,0]];
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement