Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Test.QuickCheck
- import Data.Maybe
- import Data.Char
- import Data.List
- -------------------------------------------------------------------------
- -- | Representation of sudoku puzzlese (allows some junk)
- data Sudoku = Sudoku { rows :: [[Maybe Int]] }
- deriving ( Show, Eq )
- -- | A sample sudoku puzzle
- example :: Sudoku
- example =
- Sudoku
- [ [j 3,j 6,n ,n ,j 7,j 1,j 2,n ,n ]
- , [n ,j 5,n ,n ,n ,n ,j 1,j 8,n ]
- , [n ,n ,j 9,j 2,n ,j 4,j 7,n ,n ]
- , [n ,n ,n ,n ,j 1,j 3,n ,j 2,j 8]
- , [j 4,n ,n ,j 5,n ,j 2,n ,n ,j 9]
- , [j 2,j 7,n ,j 4,j 6,n ,n ,n ,n ]
- , [n ,n ,j 5,j 3,n ,j 8,j 9,n ,n ]
- , [n ,j 8,j 3,n ,n ,n ,n ,j 6,n ]
- , [n ,n ,j 7,j 6,j 9,n ,n ,j 4,j 3]
- ]
- where
- n = Nothing
- j = Just
- -- * A1
- -- | allBlankSudoku is a sudoku with just blanks
- --allBlankSudoku :: Sudoku, Check all the rows, columns, is the type Sudoku?
- allBlankSudoku = Sudoku (replicate 9 (replicate 9 Nothing))
- -- * A2
- -- | isSudoku sud checks if sud is really a valid representation of a sudoku
- -- puzzle
- -- does the sudoku have 9 rows? Does it have 9 columns? Are the digits between 1-9?
- -- a
- isSudoku :: Sudoku -> Bool
- isSudoku (Sudoku r) = checkRows r && checkCols r && checkDigit (getList r)
- checkRows :: [[Maybe Int]] -> Bool
- checkRows [] = True
- checkRows (x:xs)
- | length x == 9 = checkRows xs
- | otherwise = False
- checkCols :: [[Maybe Int]] -> Bool
- checkCols c = length c == 9
- checkDigit :: [Maybe Int] -> Bool
- checkDigit [] = True
- checkDigit (x:xs)
- | isNothing x = checkDigit xs
- | (fromMaybe 0 x > 0) && (fromMaybe 0 x < 10) = checkDigit xs
- | otherwise = False
- getList :: [[Maybe Int]] -> [Maybe Int]
- getList x = [ z | y <- x, z <- y]
- -- * A3
- -- | isFilled sud checks if sud is completely filled in,
- -- i.e. there are no blanks
- isFilled :: Sudoku -> Bool
- isFilled (Sudoku r) = Nothing `notElem` getList r
- -------------------------------------------------------------------------
- -- * B1
- -- |b printSudoku sud prints a nice representation of the sudoku sud on
- -- the screen
- printSudoku :: Sudoku -> IO ()
- printSudoku (Sudoku x) = printList ((map . map) printSign x)
- where printList (x:xs) = do
- mapM_ putStr x -- Use mapM_ for putStr on every Char.
- putStrLn "" -- Create new line after all of above are printed.
- if null xs then putStr "" -- Make recursive call.
- else printList xs
- -- | Make a function, if it receives Nothing, then print a "." otherwise print
- -- the number
- printSign :: (Show a) => Maybe a -> String
- printSign m
- | isNothing m = "."
- | otherwise = show . fromJust $ m
- -- * B2
- -- | readSudoku file reads from the file, and either delivers it, or stops
- -- if the file did not contain a sudoku
- readSudoku :: FilePath -> IO Sudoku
- readSudoku f = do
- file <- readFile f
- let getlines = lines file
- let x = map convertToMaybeList getlines
- let y = convertToSudoku x
- if isSudoku y then return y
- else error "Bad read"
- convertToSudoku :: [[Maybe Int]] -> Sudoku
- convertToSudoku = Sudoku
- convertToMaybeList :: String -> [Maybe Int]
- convertToMaybeList [] = []
- convertToMaybeList (x:xs)
- | isDigit x = Just (digitToInt x) : convertToMaybeList xs
- | otherwise = Nothing : convertToMaybeList xs
- -------------------------------------------------------------------------
- -- * C1
- -- | cell generates an arbitrary cell in a Sudoku, for every 8 Nothing there will be
- -- 2 values of (Just n)
- cell :: Gen (Maybe Int)
- cell = frequency [(8, return Nothing),(2, getJust)]
- -- | Generate a random Just value on the range 1..9
- getJust :: Gen (Maybe Int)
- getJust = do
- i <- choose (1,9)
- return (Just i)
- -- * C2
- -- | an instance for generating Arbitrary Sudokus
- instance Arbitrary Sudoku where
- arbitrary =
- do rows <- vectorOf 9 (vectorOf 9 cell)
- return (Sudoku rows)
- -- * C3
- prop_Sudoku :: Sudoku -> Bool
- prop_Sudoku = isSudoku
- -------------------------------------------------------------------------
- -- Idea is that we must take an element, then compare it to every other element in
- -- the rest of the list. If it already exists then ready false, otherwise return ok
- -- and continue with next element, if we reach end of list then return true
- -- If we get continue, maybe another recursive call.
- type Block = [Maybe Int]
- -- | Checks so that every element of a block is unique.
- isOkayBlock :: Block -> Bool
- isOkayBlock [] = True
- isOkayBlock (b:bs)
- | isNothing b = isOkayBlock bs
- | compareBlock b bs = isOkayBlock bs
- | otherwise = False
- -- | Helper function to isOkayBlock, compares an element to every other in the list.
- compareBlock :: Maybe Int -> Block -> Bool
- compareBlock _ [] = True
- compareBlock a (b:bs)
- | a == b = False
- | otherwise = compareBlock a bs
- -- | Given a Sudoku, creates a list of lists that contain all the possible blocks for
- -- a sudoku.
- blocks :: Sudoku -> [Block]
- blocks sudo@(Sudoku b) = getColumns b ++ getRows b ++ getSquares sudo
- -- | Get columns of a the blocks by using the transpose function
- getColumns :: [[Maybe Int]] -> [Block]
- getColumns = transpose
- -- | The rows are simply all of the lists inside the list.
- getRows :: [[Maybe Int]] -> [Block]
- getRows b = b
- -- | Make calls from 0..2 to get all the blocks.
- getSquares :: Sudoku -> [Block]
- getSquares (Sudoku b) = [ squares b (x,y) | x <- [0..2], y <- [0..2]]
- -- | Input determines how many elements to drop from a row and column in order to get the
- -- right block.
- squares :: [[Maybe Int]] -> (Int, Int) -> [Maybe Int]
- squares b (n, m) = concatMap (take 3 . drop (3 * n)) (take 3 (drop (m * 3) b))
- --concat ((map (take 3 . drop (3*n)) ( take 3 (drop (m*3) b))))
- -- | This property check that for each Sudoku, there are 3*9 blocks, and each block
- -- has exactly 9 cells.
- prop_blockCheck :: Sudoku -> Bool
- prop_blockCheck sudo@(Sudoku b) =
- length (blocks sudo) == 27
- && (False `notElem` map (\x -> length x == 9) b)
- -- | Use map onto every block in the list of lists and then check if a False value is
- -- part of the list, if it is not, then the blocks are ok.
- isOkay :: Sudoku -> Bool
- isOkay bs = False `notElem` map isOkayBlock (blocks bs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement