Advertisement
Guest User

Untitled

a guest
Apr 27th, 2017
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import Data.List
  2. import Data.Char
  3. import System.Random
  4. import Test.QuickCheck
  5. import Data.Maybe
  6.  
  7. type Block = [Maybe Int]
  8. type Pos = (Int, Int)
  9.  
  10. data Sudoku = Sudoku [[Maybe Int]]
  11.   deriving(Eq, Show)
  12.  
  13. rows :: Sudoku -> [[Maybe Int]]
  14. rows (Sudoku rs) = rs
  15.  
  16. example :: Sudoku
  17. example =
  18.   Sudoku
  19.     [ [Just 3, Just 6, Nothing,Nothing,Just 7, Just 1, Just 2, Nothing,Nothing]
  20.     , [Nothing,Just 5, Nothing,Nothing,Nothing,Nothing,Just 1, Just 8, Nothing]
  21.     , [Nothing,Nothing,Just 9, Just 2, Nothing,Just 4, Just 7, Nothing,Nothing]
  22.     , [Nothing,Nothing,Nothing,Nothing,Just 1, Just 3, Nothing,Just 2, Just 8]
  23.     , [Just 4, Nothing,Nothing,Just 5, Nothing,Just 2, Nothing,Nothing,Just 9]
  24.     , [Just 2, Just 7, Nothing,Just 4, Just 6, Nothing,Nothing,Nothing,Nothing]
  25.     , [Nothing,Nothing,Just 5, Just 3, Nothing,Just 8, Just 9, Nothing,Nothing]
  26.     , [Nothing,Just 8, Just 3, Nothing,Nothing,Nothing,Nothing,Just 6, Nothing]
  27.     , [Nothing,Nothing,Just 7, Just 6, Just 9, Nothing,Nothing,Just 4, Just 3]
  28.     ]
  29.    
  30.  
  31. example2 :: Sudoku
  32. example2 = Sudoku(map reverse (rows example))
  33.  
  34.  
  35. example3 :: Sudoku
  36. example3 = Sudoku(reverse (rows example))
  37.  
  38.  
  39.  
  40. -- Task A)
  41.  
  42. -- 1)
  43.  
  44. -- y <- [1..9] skapar 9 listor av x <- [1..9] som är fyllda med Nothing
  45. allBlankSudoku :: Sudoku
  46. allBlankSudoku = Sudoku [ [ Nothing | x <- [1..9] ] | y <- [1..9] ]
  47.  
  48.  
  49. -- Gör om Sudoku till lista av listor, sedan till en lång lista med concat.
  50. sudokuList :: Sudoku -> [Maybe Int]
  51. sudokuList s = (concat (rows s))
  52.  
  53. -- 2)
  54. -- Är det 9 listor av 9 element där alla är MaybeInt under 10? (Nothing räknas med här)
  55. isSudoku :: Sudoku -> Bool
  56. isSudoku s = all (==9) (map length (rows s))    &&
  57.                 length (rows s) == 9    &&
  58.                 all (isSudokuHelper) (concat(rows s))
  59.  
  60. isSudokuHelper Nothing = True
  61. isSudokuHelper (Just n) = n > 0 && n < 10
  62.              
  63. --isSudukoHelper n
  64. -- 3)
  65. -- Är alla rutor fyllda med en MaybeInt som inte är Nothing? (vi kanske borde kolla om dom är under 10 också..?)
  66. isSolved :: Sudoku -> Bool
  67. isSolved s = all (> Just 0) (sudokuList s)
  68.  
  69.  
  70. -- Task B)
  71.  
  72. -- 1)
  73. --printa SudokuToList
  74. printSudoku :: Sudoku -> IO ()
  75. printSudoku s = putStrLn (sudokuToString s)
  76.  
  77. --rows s blir en lista av listor med Maybe Int
  78. --map showSudoku rows listorna av MaybeInt till strängar av siffor och punkter
  79. --    Just x:xs om första elementet är en Maybe int... gör om till char digit och sedan rekursion
  80. --    Nothing:xs annars om det är Nothing, gör en punkt och sedan rekursion
  81. --    Unlines gör om listan av strängar till en lång sträng med radbryt efter varje "lista"
  82. sudokuToString:: Sudoku -> String
  83. sudokuToString s = unlines(map(showSudoku) (rows s))
  84.  
  85. showSudoku :: [Maybe Int] -> String
  86. showSudoku [] = ""
  87. showSudoku (Nothing:xs) = "." ++ showSudoku xs
  88. showSudoku (Just x:xs) = [intToDigit x] ++ showSudoku xs
  89.  
  90. -- 2)
  91. --Removes spaces from string and coverts to list of matbe ints, takestuff converts to list of 9 lists
  92. --Sudoku [[MaybeInt]]
  93. readSudoku :: FilePath -> IO Sudoku
  94. readSudoku fp = do
  95.     f <- readFile fp
  96.     let sud = Sudoku (map convertStringToMaybeInts (lines f))
  97.     if not(isSudoku sud)
  98.       then error "Sorry mate, you ain't loading any other files than .sud"
  99.     else return(sud)
  100.  
  101. --takeStuff :: [a] -> Int -> [[a]]
  102. takeStuff [] _ = []
  103. takeStuff list a = (take a list) : takeStuff (drop a list) a
  104.  
  105. --convertStringToSudokuList :: String -> [[Maybe Int]]
  106. --convertStringToSudokuList s = lines (convertStringToMaybeInts s)
  107.  
  108. convertStringToMaybeInts :: String -> [Maybe Int]
  109. convertStringToMaybeInts "" =  []
  110. convertStringToMaybeInts ('.':xs) = [Nothing] ++ convertStringToMaybeInts xs
  111. convertStringToMaybeInts (x:xs) = [Just (digitToInt x)] ++ convertStringToMaybeInts xs
  112.  
  113. -- Task C)
  114.  
  115. -- 1)
  116.  
  117. cell :: Gen (Maybe Int)
  118. cell = frequency [
  119.                   (9, return Nothing),
  120.                   (1, do n <- choose(1, 9)
  121.                          return(Just n))
  122.                   ]
  123.  
  124. -- 2)
  125.  
  126. instance Arbitrary Sudoku where
  127.   arbitrary =
  128.     do r <- sequence [ sequence [ cell | x <- [1..9] ] | y <- [1..9] ]
  129.        return (Sudoku r)
  130.  
  131. -- 3)
  132.  
  133. prop_Sudoku :: Sudoku -> Bool
  134. prop_Sudoku = isSudoku
  135.  
  136.  
  137.  
  138.  
  139. -- Task D 1)
  140.  
  141. isOkayBlock :: Int -> Sudoku -> Bool
  142. isOkayBlock n s = lengthWithoutDups [(block n s)] s == lengthWithDups [(block n s)]
  143.  
  144.  
  145. -- 2)
  146. {-
  147. gets a 3x3 block from the sudoku, 0 is first block and 8 is the last
  148. offSet 6 gives the second row of blocks, and offset 12 gives the third...
  149. blockRow gives a list of list of 3 elements, a list of 3 is 1 part of a block...
  150. -}
  151. block :: Int -> Sudoku -> Block
  152. block n s   = (blockRow (n+(offSet n)) ++ blockRow (n+(offSet n)+3) ++ blockRow (n+(offSet n)+6))
  153.     where
  154.         blockRow x = takeStuff (sudokuList s) 3 !! x
  155.         offSet n | n<3 = 0
  156.                  | n>5 = 12
  157.                  | otherwise = 6
  158.  
  159. --get all 9 3x3 blocks from a sudoku
  160. blocks :: Sudoku -> [Block]
  161. blocks s = [ block n s | n <- [0..8] ]
  162.  
  163. prop_blocks :: Sudoku -> Bool
  164. prop_blocks s = length(blocks s) == 9 && all (==9) (map length (blocks s))
  165.  
  166. --get all 9 columns from a sudoku
  167. columns :: Sudoku -> [Block]
  168. columns s = transpose (rows s)
  169.  
  170. -- 3)
  171. --Remove duplicates from columns, rows and blocks and compare length (empty squares are not counted as duplicates)
  172. isOkay :: Sudoku -> Bool
  173. isOkay s = isOkayRows s && isOkayColumns s && isOkayBlocks s
  174.  
  175. isOkayBlocks :: Sudoku -> Bool
  176. isOkayBlocks s = lengthWithoutDups (blocks s) s == lengthWithDups (blocks s)
  177.  
  178. isOkayRows :: Sudoku -> Bool
  179. isOkayRows s = lengthWithoutDups (rows s) s == lengthWithDups (rows s)
  180.  
  181. isOkayColumns :: Sudoku -> Bool
  182. isOkayColumns s = lengthWithoutDups (columns s) s == lengthWithDups (columns s)
  183.              
  184. lengthWithoutDups :: (Ord a, Num a) => [[Maybe a]] -> t -> [Int]
  185. lengthWithoutDups l s = map length (noDuplicatesIn l s)      
  186.  
  187. lengthWithDups :: (Ord a, Num a) => [[Maybe a]] -> [Int]
  188. lengthWithDups l = map (length ) (withoutEmptySquares l)
  189.        
  190. withoutEmptySquares :: (Ord a, Num a) => [[Maybe a]] -> [[Maybe a]]
  191. withoutEmptySquares l = map (filter (>Just 0)) l
  192.  
  193. noDuplicatesIn :: (Ord a, Num a) => [[Maybe a]] -> t -> [[Maybe a]]
  194. noDuplicatesIn l s = map nub (withoutEmptySquares l)
  195.  
  196. -- Task E 1)
  197.  
  198. --returns position of the first blank space as tuple
  199. blank :: Sudoku -> Pos
  200. blank s = (y, x)
  201.     where
  202.         Just index = elemIndex Nothing (sudokuList s)
  203.         x = (index ) `mod` 9
  204.         y = (index ) `div` 9
  205.          
  206. prop_blank :: Sudoku -> Bool
  207. prop_blank s = (((rows s) !! row) !! col) == Nothing
  208.     where
  209.         (row, col) = blank s
  210.  
  211. --Task E 2)
  212.  
  213. (!!=) :: [a] -> (Int, a) -> [a]
  214. (!!=) list (i, v) | i > (length list - 1) || i < 0  = list
  215.                   | otherwise = (fst(splitAt i list)) ++ v : drop 1 (snd(splitAt i list))
  216.  
  217. prop_replaceOperator :: [a] -> (Int, a) -> Bool
  218. prop_replaceOperator list (i, v) = length list == length (list !!= (i, v))
  219.  
  220.  
  221. --Task E  3)
  222.  
  223. update :: Sudoku -> Pos -> Maybe Int -> Sudoku
  224. update s (y, x) Nothing = Sudoku (takeStuff ((concat (rows s)) !!= ((ind (y,x)),(Nothing))) 9)
  225. update s (y, x) (Just n)
  226.  | n < 1 || n > 9 = s
  227.  | otherwise = Sudoku (takeStuff ((concat (rows s)) !!= ((ind (y,x)),(Just n))) 9)
  228.  
  229.  
  230.  
  231. ind :: (Int,Int) -> Int
  232. ind (y,x) =(9 * y) + x
  233.  
  234. prop_update :: Sudoku -> Bool
  235. prop_update s = (((rows (update s (blank s) (Just 1))) !! (fst (blank s))) !! (snd(blank s))) == (Just 1)
  236.  
  237.  
  238.  
  239. solve :: Sudoku -> Maybe Sudoku
  240. solve s | not(isOkay s) = Nothing  -- There's a violation in s
  241.         | isSolved s    = Just s   -- s is already solved
  242.         | otherwise = pickASolution possibleSolutions
  243.   where
  244.     nineUpdatedSuds = [update s (blank s) (Just v) | v <- [1..9] ]
  245.     possibleSolutions = [solve s' | s' <- nineUpdatedSuds]
  246.  
  247.  
  248. pickASolution :: [Maybe Sudoku] -> Maybe Sudoku
  249. pickASolution [] = Nothing
  250. pickASolution suds | solutions == [] = Nothing
  251.                    | otherwise  = Just (head solutions)
  252.   where
  253.    solutions = (filter isOkay (map (fromJust) (filter (/= Nothing) suds)))
  254.  
  255. -- Task F 2)
  256.  
  257. readAndSolve :: FilePath -> IO ()
  258. readAndSolve fp = do
  259.     f <- readSudoku fp
  260.     putStrLn "Solution to given example: \n"
  261.     printSudoku (fromJust (solve f))
  262.  
  263.  
  264. --Task F 3)
  265. isSolutionOf :: Sudoku -> Sudoku -> Bool
  266. isSolutionOf s1 s2 = (isOkay s1) && (isSolved s1) && (digitsFromSameAs s1 s2)  
  267.  
  268. allDigitsIndicesFrom :: Sudoku -> [Int]
  269. allDigitsIndicesFrom s = concat $ [elemIndices (Just n) (sudokuList s) | n <- [1..9]]
  270.  
  271. digitsFromSameAs :: Sudoku -> Sudoku -> Bool
  272. digitsFromSameAs s1 s2 = all (==True)[(((sudokuList s1) !! n) == ((sudokuList s2) !! n)) | n <- (allDigitsIndicesFrom s2)]
  273.  
  274.  
  275.  
  276. --Task F 4)
  277. prop_SolveSound :: Sudoku -> Property
  278. prop_SolveSound s = (solve s /= Nothing) ==> fromJust(solve s) `isSolutionOf` s
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement