Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Data.List
- import Data.Char
- import System.Random
- import Test.QuickCheck
- import Data.Maybe
- type Block = [Maybe Int]
- type Pos = (Int, Int)
- data Sudoku = Sudoku [[Maybe Int]]
- deriving(Eq, Show)
- rows :: Sudoku -> [[Maybe Int]]
- rows (Sudoku rs) = rs
- example :: Sudoku
- example =
- Sudoku
- [ [Just 3, Just 6, Nothing,Nothing,Just 7, Just 1, Just 2, Nothing,Nothing]
- , [Nothing,Just 5, Nothing,Nothing,Nothing,Nothing,Just 1, Just 8, Nothing]
- , [Nothing,Nothing,Just 9, Just 2, Nothing,Just 4, Just 7, Nothing,Nothing]
- , [Nothing,Nothing,Nothing,Nothing,Just 1, Just 3, Nothing,Just 2, Just 8]
- , [Just 4, Nothing,Nothing,Just 5, Nothing,Just 2, Nothing,Nothing,Just 9]
- , [Just 2, Just 7, Nothing,Just 4, Just 6, Nothing,Nothing,Nothing,Nothing]
- , [Nothing,Nothing,Just 5, Just 3, Nothing,Just 8, Just 9, Nothing,Nothing]
- , [Nothing,Just 8, Just 3, Nothing,Nothing,Nothing,Nothing,Just 6, Nothing]
- , [Nothing,Nothing,Just 7, Just 6, Just 9, Nothing,Nothing,Just 4, Just 3]
- ]
- example2 :: Sudoku
- example2 = Sudoku(map reverse (rows example))
- example3 :: Sudoku
- example3 = Sudoku(reverse (rows example))
- -- Task A)
- -- 1)
- -- y <- [1..9] skapar 9 listor av x <- [1..9] som är fyllda med Nothing
- allBlankSudoku :: Sudoku
- allBlankSudoku = Sudoku [ [ Nothing | x <- [1..9] ] | y <- [1..9] ]
- -- Gör om Sudoku till lista av listor, sedan till en lång lista med concat.
- sudokuList :: Sudoku -> [Maybe Int]
- sudokuList s = (concat (rows s))
- -- 2)
- -- Är det 9 listor av 9 element där alla är MaybeInt under 10? (Nothing räknas med här)
- isSudoku :: Sudoku -> Bool
- isSudoku s = all (==9) (map length (rows s)) &&
- length (rows s) == 9 &&
- all (isSudokuHelper) (concat(rows s))
- isSudokuHelper Nothing = True
- isSudokuHelper (Just n) = n > 0 && n < 10
- --isSudukoHelper n
- -- 3)
- -- Är alla rutor fyllda med en MaybeInt som inte är Nothing? (vi kanske borde kolla om dom är under 10 också..?)
- isSolved :: Sudoku -> Bool
- isSolved s = all (> Just 0) (sudokuList s)
- -- Task B)
- -- 1)
- --printa SudokuToList
- printSudoku :: Sudoku -> IO ()
- printSudoku s = putStrLn (sudokuToString s)
- --rows s blir en lista av listor med Maybe Int
- --map showSudoku rows listorna av MaybeInt till strängar av siffor och punkter
- -- Just x:xs om första elementet är en Maybe int... gör om till char digit och sedan rekursion
- -- Nothing:xs annars om det är Nothing, gör en punkt och sedan rekursion
- -- Unlines gör om listan av strängar till en lång sträng med radbryt efter varje "lista"
- sudokuToString:: Sudoku -> String
- sudokuToString s = unlines(map(showSudoku) (rows s))
- showSudoku :: [Maybe Int] -> String
- showSudoku [] = ""
- showSudoku (Nothing:xs) = "." ++ showSudoku xs
- showSudoku (Just x:xs) = [intToDigit x] ++ showSudoku xs
- -- 2)
- --Removes spaces from string and coverts to list of matbe ints, takestuff converts to list of 9 lists
- --Sudoku [[MaybeInt]]
- readSudoku :: FilePath -> IO Sudoku
- readSudoku fp = do
- f <- readFile fp
- let sud = Sudoku (map convertStringToMaybeInts (lines f))
- if not(isSudoku sud)
- then error "Sorry mate, you ain't loading any other files than .sud"
- else return(sud)
- --takeStuff :: [a] -> Int -> [[a]]
- takeStuff [] _ = []
- takeStuff list a = (take a list) : takeStuff (drop a list) a
- --convertStringToSudokuList :: String -> [[Maybe Int]]
- --convertStringToSudokuList s = lines (convertStringToMaybeInts s)
- convertStringToMaybeInts :: String -> [Maybe Int]
- convertStringToMaybeInts "" = []
- convertStringToMaybeInts ('.':xs) = [Nothing] ++ convertStringToMaybeInts xs
- convertStringToMaybeInts (x:xs) = [Just (digitToInt x)] ++ convertStringToMaybeInts xs
- -- Task C)
- -- 1)
- cell :: Gen (Maybe Int)
- cell = frequency [
- (9, return Nothing),
- (1, do n <- choose(1, 9)
- return(Just n))
- ]
- -- 2)
- instance Arbitrary Sudoku where
- arbitrary =
- do r <- sequence [ sequence [ cell | x <- [1..9] ] | y <- [1..9] ]
- return (Sudoku r)
- -- 3)
- prop_Sudoku :: Sudoku -> Bool
- prop_Sudoku = isSudoku
- -- Task D 1)
- isOkayBlock :: Int -> Sudoku -> Bool
- isOkayBlock n s = lengthWithoutDups [(block n s)] s == lengthWithDups [(block n s)]
- -- 2)
- {-
- gets a 3x3 block from the sudoku, 0 is first block and 8 is the last
- offSet 6 gives the second row of blocks, and offset 12 gives the third...
- blockRow gives a list of list of 3 elements, a list of 3 is 1 part of a block...
- -}
- block :: Int -> Sudoku -> Block
- block n s = (blockRow (n+(offSet n)) ++ blockRow (n+(offSet n)+3) ++ blockRow (n+(offSet n)+6))
- where
- blockRow x = takeStuff (sudokuList s) 3 !! x
- offSet n | n<3 = 0
- | n>5 = 12
- | otherwise = 6
- --get all 9 3x3 blocks from a sudoku
- blocks :: Sudoku -> [Block]
- blocks s = [ block n s | n <- [0..8] ]
- prop_blocks :: Sudoku -> Bool
- prop_blocks s = length(blocks s) == 9 && all (==9) (map length (blocks s))
- --get all 9 columns from a sudoku
- columns :: Sudoku -> [Block]
- columns s = transpose (rows s)
- -- 3)
- --Remove duplicates from columns, rows and blocks and compare length (empty squares are not counted as duplicates)
- isOkay :: Sudoku -> Bool
- isOkay s = isOkayRows s && isOkayColumns s && isOkayBlocks s
- isOkayBlocks :: Sudoku -> Bool
- isOkayBlocks s = lengthWithoutDups (blocks s) s == lengthWithDups (blocks s)
- isOkayRows :: Sudoku -> Bool
- isOkayRows s = lengthWithoutDups (rows s) s == lengthWithDups (rows s)
- isOkayColumns :: Sudoku -> Bool
- isOkayColumns s = lengthWithoutDups (columns s) s == lengthWithDups (columns s)
- lengthWithoutDups :: (Ord a, Num a) => [[Maybe a]] -> t -> [Int]
- lengthWithoutDups l s = map length (noDuplicatesIn l s)
- lengthWithDups :: (Ord a, Num a) => [[Maybe a]] -> [Int]
- lengthWithDups l = map (length ) (withoutEmptySquares l)
- withoutEmptySquares :: (Ord a, Num a) => [[Maybe a]] -> [[Maybe a]]
- withoutEmptySquares l = map (filter (>Just 0)) l
- noDuplicatesIn :: (Ord a, Num a) => [[Maybe a]] -> t -> [[Maybe a]]
- noDuplicatesIn l s = map nub (withoutEmptySquares l)
- -- Task E 1)
- --returns position of the first blank space as tuple
- blank :: Sudoku -> Pos
- blank s = (y, x)
- where
- Just index = elemIndex Nothing (sudokuList s)
- x = (index ) `mod` 9
- y = (index ) `div` 9
- prop_blank :: Sudoku -> Bool
- prop_blank s = (((rows s) !! row) !! col) == Nothing
- where
- (row, col) = blank s
- --Task E 2)
- (!!=) :: [a] -> (Int, a) -> [a]
- (!!=) list (i, v) | i > (length list - 1) || i < 0 = list
- | otherwise = (fst(splitAt i list)) ++ v : drop 1 (snd(splitAt i list))
- prop_replaceOperator :: [a] -> (Int, a) -> Bool
- prop_replaceOperator list (i, v) = length list == length (list !!= (i, v))
- --Task E 3)
- update :: Sudoku -> Pos -> Maybe Int -> Sudoku
- update s (y, x) Nothing = Sudoku (takeStuff ((concat (rows s)) !!= ((ind (y,x)),(Nothing))) 9)
- update s (y, x) (Just n)
- | n < 1 || n > 9 = s
- | otherwise = Sudoku (takeStuff ((concat (rows s)) !!= ((ind (y,x)),(Just n))) 9)
- ind :: (Int,Int) -> Int
- ind (y,x) =(9 * y) + x
- prop_update :: Sudoku -> Bool
- prop_update s = (((rows (update s (blank s) (Just 1))) !! (fst (blank s))) !! (snd(blank s))) == (Just 1)
- solve :: Sudoku -> Maybe Sudoku
- solve s | not(isOkay s) = Nothing -- There's a violation in s
- | isSolved s = Just s -- s is already solved
- | otherwise = pickASolution possibleSolutions
- where
- nineUpdatedSuds = [update s (blank s) (Just v) | v <- [1..9] ]
- possibleSolutions = [solve s' | s' <- nineUpdatedSuds]
- pickASolution :: [Maybe Sudoku] -> Maybe Sudoku
- pickASolution [] = Nothing
- pickASolution suds | solutions == [] = Nothing
- | otherwise = Just (head solutions)
- where
- solutions = (filter isOkay (map (fromJust) (filter (/= Nothing) suds)))
- -- Task F 2)
- readAndSolve :: FilePath -> IO ()
- readAndSolve fp = do
- f <- readSudoku fp
- putStrLn "Solution to given example: \n"
- printSudoku (fromJust (solve f))
- --Task F 3)
- isSolutionOf :: Sudoku -> Sudoku -> Bool
- isSolutionOf s1 s2 = (isOkay s1) && (isSolved s1) && (digitsFromSameAs s1 s2)
- allDigitsIndicesFrom :: Sudoku -> [Int]
- allDigitsIndicesFrom s = concat $ [elemIndices (Just n) (sudokuList s) | n <- [1..9]]
- digitsFromSameAs :: Sudoku -> Sudoku -> Bool
- digitsFromSameAs s1 s2 = all (==True)[(((sudokuList s1) !! n) == ((sudokuList s2) !! n)) | n <- (allDigitsIndicesFrom s2)]
- --Task F 4)
- prop_SolveSound :: Sudoku -> Property
- prop_SolveSound s = (solve s /= Nothing) ==> fromJust(solve s) `isSolutionOf` s
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement