module Exercise03 where import Data.List (elemIndex, intercalate, nub, (\\)) import qualified Data.Maybe import Text.Printf (printf) -- HA 3.1a) i selectRow :: [[Int]] -> Int -> [Int] selectRow xss i = xss !! i -- HA 3.1a) ii selectColumn :: [[Int]] -> Int -> [Int] selectColumn xss i = [xs !! i | xs <- xss] -- HA 3.1a) iii intRoot :: Int -> Int intRoot = floor . sqrt . fromIntegral --return numbers in square as a list. squares are numbered from left to right and top to bottom --e.g. : --[0,1,2] --[3,4,5] --[6,7,8] selectSquare :: [[Int]] -> Int -> [Int] selectSquare xss i = let root = intRoot (length xss) size = length xss in [ selectRow xss row !! col | row <- [0 .. (size -1)], row >= i `div` root * root, row < i `div` root * root + root, col <- [0 .. (size -1)], col >= i `mod` root * root, col < i `mod` root * root + root ] -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = length numbers == length (nub numbers) where numbers = filter (/= 0) xs uniqueNumbers :: [Int] -> [Int] uniqueNumbers xs = nub (filter (/= 0) xs) isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and [ isValidSubsection (selectRow xss i) && isValidSubsection (selectColumn xss i) && isValidSubsection (selectSquare xss i) | i <- [0 .. (length xss -1)] ] -- HA 3.1c) setCell :: [[Int]] -> (Int, Int) -> Int -> [[Int]] setCell xss (row, col) value = let (frontRows, modRow : backRows) = splitAt row xss (frontValues, x : backValues) = splitAt col modRow in frontRows ++ [frontValues ++ [value] ++ backValues] ++ backRows -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku sudoku | fst nextNull == -1 && isValidSudoku sudoku = sudoku | fst nextNull == -1 && not (isValidSudoku sudoku) = [] | otherwise = foldl ( \sofar value -> if not (null sofar) then sofar else solveSudoku (setCell sudoku nextNull value) ) [] (possibleNumbers sudoku nextNull) where nextNull = nextNullIndex (concat sudoku) (length sudoku) myfun :: [[Int]] -> Int -> [[Int]] myfun sudoku value | not (null sudoku) = sudoku | otherwise = solveSudoku (setCell sudoku nextNull value) where nextNull = nextNullIndex (concat sudoku) (length sudoku) hasZeros :: [[Int]] -> Bool hasZeros xss = Data.Maybe.isJust (elemIndex 0 (concat xss)) possibleNumbers :: [[Int]] -> (Int, Int) -> [Int] possibleNumbers sudoku (row, col) = let size = length sudoku root = intRoot size squareRow = (row `div` root) * root squareCol = col `div` root square = squareRow + squareCol in [1 .. size] \\ uniqueNumbers ( selectColumn sudoku col ++ selectRow sudoku row ++ selectSquare sudoku square ) nextNullIndex :: [Int] -> Int -> (Int, Int) nextNullIndex values size | Data.Maybe.isNothing index = (-1, -1) | otherwise = ( Data.Maybe.fromMaybe 0 index `div` size, Data.Maybe.fromMaybe 0 index `mod` size ) where index = elemIndex 0 values {-TTEW-} hardSudoku :: [[Int]] hardSudoku = [ [8, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 6, 0, 0, 0, 0, 0], [0, 7, 0, 0, 9, 0, 2, 0, 0], [0, 5, 0, 0, 0, 7, 0, 0, 0], [0, 0, 0, 0, 4, 5, 7, 0, 0], [0, 0, 0, 1, 0, 0, 0, 3, 0], [0, 0, 1, 0, 0, 0, 0, 6, 8], [0, 0, 8, 5, 0, 0, 0, 1, 0], [0, 9, 0, 0, 0, 0, 4, 0, 0] ] easySudoku :: [[Int]] easySudoku = [ [1, 2, 0, 0], [3, 4, 1, 2], [4, 3, 2, 1], [2, 0, 4, 3] ] -- Utility method to show a sudoku -- show sudoku with -- >>> putStr (showSudoku sudoku) showSudoku :: [[Int]] -> String showSudoku xss = unlines $ intercalate [showDivider] $ chunksOf squareSize $ map showRow xss where size = length xss squareSize = intRoot size numberSize = size `div` 10 + 1 showRowSection xs = unwords $ map (printf ("%0" ++ show numberSize ++ "d")) xs showRow xs = intercalate "|" $ map showRowSection $ chunksOf squareSize xs showDivider = intercalate "+" $ replicate squareSize $ replicate ((numberSize + 1) * squareSize - 1) '-' chunksOf :: Int -> [e] -> [[e]] chunksOf i [] = [] chunksOf i ls = take i ls : chunksOf i (drop i ls)