module Exercise03 where import Text.Printf (printf) import Data.List import Control.Monad (guard) import Data.Maybe -- 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 = concat (getColumns xss i) getColumns :: [[Int]] -> Int -> [[Int]] getColumns xss i = [take (intRoot (length xss)) (drop (horiOffset xss i) row) | row <- getRows xss i] getRows :: [[Int]] -> Int -> [[Int]] getRows xss i = take (intRoot (length xss)) (drop (vertOffset xss i) xss) vertOffset :: [[Int]] -> Int -> Int vertOffset xss i = (i `div` x) * x where x = intRoot (length xss) horiOffset :: [[Int]] -> Int -> Int horiOffset xss i = (i `mod` x) * x where x = intRoot (length xss) -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = nub (filter (>0) xs) == filter (>0) xs isValidSudoku :: [[Int]] -> Bool isValidSudoku xss | not (null 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 (k, j) x = top ++ ((left ++ (x:right)):bot) where left = take j (xss!!k) right = take (length xss - j - 1) (drop (j + 1) (xss!!k)) top = take k xss bot = take (length xss - k - 1) (drop (k + 1) xss) -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss | null possibilities = [] | otherwise = head possibilities where possibilities = recSolve xss (nextCell xss) recSolve :: [[Int]] -> Maybe (Int, Int) -> [[[Int]]] recSolve xss cords = if isNothing cords then [xss] else do n <- [1 .. length xss] let newMatrix = setCell xss (fromJust cords) n guard (isValidSudoku newMatrix) recSolve newMatrix (nextCell xss) nextCell :: [[Int]] -> Maybe (Int, Int) nextCell xss = if isNothing potentialPos then Nothing else Just (fromJust potentialPos `div` length xss, fromJust potentialPos `mod` length xss) where potentialPos = elemIndex 0 (concat xss) {-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]] -- 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)