Advertisement
Guest User

Untitled

a guest
Nov 22nd, 2017
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.23 KB | None | 0 0
  1.  
  2. import Test.QuickCheck
  3. import Data.Maybe
  4. import Data.Char
  5. import Data.List
  6. -------------------------------------------------------------------------
  7.  
  8. -- | Representation of sudoku puzzlese (allows some junk)
  9. data Sudoku = Sudoku { rows :: [[Maybe Int]] }
  10. deriving ( Show, Eq )
  11.  
  12.  
  13.  
  14.  
  15. -- | A sample sudoku puzzle
  16. example :: Sudoku
  17. example =
  18. Sudoku
  19. [ [j 3,j 6,n ,n ,j 7,j 1,j 2,n ,n ]
  20. , [n ,j 5,n ,n ,n ,n ,j 1,j 8,n ]
  21. , [n ,n ,j 9,j 2,n ,j 4,j 7,n ,n ]
  22. , [n ,n ,n ,n ,j 1,j 3,n ,j 2,j 8]
  23. , [j 4,n ,n ,j 5,n ,j 2,n ,n ,j 9]
  24. , [j 2,j 7,n ,j 4,j 6,n ,n ,n ,n ]
  25. , [n ,n ,j 5,j 3,n ,j 8,j 9,n ,n ]
  26. , [n ,j 8,j 3,n ,n ,n ,n ,j 6,n ]
  27. , [n ,n ,j 7,j 6,j 9,n ,n ,j 4,j 3]
  28. ]
  29. where
  30. n = Nothing
  31. j = Just
  32.  
  33. -- * A1
  34.  
  35. -- | allBlankSudoku is a sudoku with just blanks
  36. --allBlankSudoku :: Sudoku, Check all the rows, columns, is the type Sudoku?
  37.  
  38. allBlankSudoku = Sudoku (replicate 9 (replicate 9 Nothing))
  39. -- * A2
  40.  
  41. -- | isSudoku sud checks if sud is really a valid representation of a sudoku
  42. -- puzzle
  43.  
  44. -- does the sudoku have 9 rows? Does it have 9 columns? Are the digits between 1-9?
  45. -- a
  46. isSudoku :: Sudoku -> Bool
  47. isSudoku (Sudoku r) = checkRows r && checkCols r && checkDigit (getList r)
  48.  
  49. checkRows :: [[Maybe Int]] -> Bool
  50. checkRows [] = True
  51. checkRows (x:xs)
  52. | length x == 9 = checkRows xs
  53. | otherwise = False
  54.  
  55. checkCols :: [[Maybe Int]] -> Bool
  56. checkCols c = length c == 9
  57.  
  58. checkDigit :: [Maybe Int] -> Bool
  59. checkDigit [] = True
  60. checkDigit (x:xs)
  61. | isNothing x = checkDigit xs
  62. | (fromMaybe 0 x > 0) && (fromMaybe 0 x < 10) = checkDigit xs
  63. | otherwise = False
  64.  
  65. getList :: [[Maybe Int]] -> [Maybe Int]
  66. getList x = [ z | y <- x, z <- y]
  67.  
  68. -- * A3
  69.  
  70. -- | isFilled sud checks if sud is completely filled in,
  71. -- i.e. there are no blanks
  72. isFilled :: Sudoku -> Bool
  73. isFilled (Sudoku r) = Nothing `notElem` getList r
  74.  
  75. -------------------------------------------------------------------------
  76.  
  77. -- * B1
  78.  
  79. -- |b printSudoku sud prints a nice representation of the sudoku sud on
  80. -- the screen
  81. printSudoku :: Sudoku -> IO ()
  82. printSudoku (Sudoku x) = printList ((map . map) printSign x)
  83. where printList (x:xs) = do
  84. mapM_ putStr x -- Use mapM_ for putStr on every Char.
  85. putStrLn "" -- Create new line after all of above are printed.
  86. if null xs then putStr "" -- Make recursive call.
  87. else printList xs
  88.  
  89. -- | Make a function, if it receives Nothing, then print a "." otherwise print
  90. -- the number
  91. printSign :: (Show a) => Maybe a -> String
  92. printSign m
  93. | isNothing m = "."
  94. | otherwise = show . fromJust $ m
  95.  
  96. -- * B2
  97.  
  98. -- | readSudoku file reads from the file, and either delivers it, or stops
  99. -- if the file did not contain a sudoku
  100.  
  101. readSudoku :: FilePath -> IO Sudoku
  102. readSudoku f = do
  103. file <- readFile f
  104. let getlines = lines file
  105. let x = map convertToMaybeList getlines
  106. let y = convertToSudoku x
  107. if isSudoku y then return y
  108. else error "Bad read"
  109.  
  110.  
  111. convertToSudoku :: [[Maybe Int]] -> Sudoku
  112. convertToSudoku = Sudoku
  113.  
  114. convertToMaybeList :: String -> [Maybe Int]
  115. convertToMaybeList [] = []
  116. convertToMaybeList (x:xs)
  117. | isDigit x = Just (digitToInt x) : convertToMaybeList xs
  118. | otherwise = Nothing : convertToMaybeList xs
  119.  
  120. -------------------------------------------------------------------------
  121.  
  122. -- * C1
  123.  
  124. -- | cell generates an arbitrary cell in a Sudoku, for every 8 Nothing there will be
  125. -- 2 values of (Just n)
  126. cell :: Gen (Maybe Int)
  127. cell = frequency [(8, return Nothing),(2, getJust)]
  128.  
  129. -- | Generate a random Just value on the range 1..9
  130. getJust :: Gen (Maybe Int)
  131. getJust = do
  132. i <- choose (1,9)
  133. return (Just i)
  134.  
  135. -- * C2
  136.  
  137. -- | an instance for generating Arbitrary Sudokus
  138.  
  139. instance Arbitrary Sudoku where
  140. arbitrary =
  141. do rows <- vectorOf 9 (vectorOf 9 cell)
  142. return (Sudoku rows)
  143.  
  144. -- * C3
  145.  
  146. prop_Sudoku :: Sudoku -> Bool
  147. prop_Sudoku = isSudoku
  148. -------------------------------------------------------------------------
  149.  
  150.  
  151. -- Idea is that we must take an element, then compare it to every other element in
  152. -- the rest of the list. If it already exists then ready false, otherwise return ok
  153. -- and continue with next element, if we reach end of list then return true
  154.  
  155. -- If we get continue, maybe another recursive call.
  156. type Block = [Maybe Int]
  157.  
  158.  
  159. -- | Checks so that every element of a block is unique.
  160. isOkayBlock :: Block -> Bool
  161. isOkayBlock [] = True
  162. isOkayBlock (b:bs)
  163. | isNothing b = isOkayBlock bs
  164. | compareBlock b bs = isOkayBlock bs
  165. | otherwise = False
  166.  
  167. -- | Helper function to isOkayBlock, compares an element to every other in the list.
  168. compareBlock :: Maybe Int -> Block -> Bool
  169. compareBlock _ [] = True
  170. compareBlock a (b:bs)
  171. | a == b = False
  172. | otherwise = compareBlock a bs
  173.  
  174. -- | Given a Sudoku, creates a list of lists that contain all the possible blocks for
  175. -- a sudoku.
  176. blocks :: Sudoku -> [Block]
  177. blocks sudo@(Sudoku b) = getColumns b ++ getRows b ++ getSquares sudo
  178.  
  179. -- | Get columns of a the blocks by using the transpose function
  180. getColumns :: [[Maybe Int]] -> [Block]
  181. getColumns = transpose
  182.  
  183. -- | The rows are simply all of the lists inside the list.
  184. getRows :: [[Maybe Int]] -> [Block]
  185. getRows b = b
  186.  
  187. -- | Make calls from 0..2 to get all the blocks.
  188. getSquares :: Sudoku -> [Block]
  189. getSquares (Sudoku b) = [ squares b (x,y) | x <- [0..2], y <- [0..2]]
  190.  
  191. -- | Input determines how many elements to drop from a row and column in order to get the
  192. -- right block.
  193. squares :: [[Maybe Int]] -> (Int, Int) -> [Maybe Int]
  194. squares b (n, m) = concatMap (take 3 . drop (3 * n)) (take 3 (drop (m * 3) b))
  195. --concat ((map (take 3 . drop (3*n)) ( take 3 (drop (m*3) b))))
  196.  
  197.  
  198.  
  199.  
  200. -- | This property check that for each Sudoku, there are 3*9 blocks, and each block
  201. -- has exactly 9 cells.
  202. prop_blockCheck :: Sudoku -> Bool
  203. prop_blockCheck sudo@(Sudoku b) =
  204. length (blocks sudo) == 27
  205. && (False `notElem` map (\x -> length x == 9) b)
  206.  
  207. -- | Use map onto every block in the list of lists and then check if a False value is
  208. -- part of the list, if it is not, then the blocks are ok.
  209. isOkay :: Sudoku -> Bool
  210. isOkay bs = False `notElem` map isOkayBlock (blocks bs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement