module Exercise03 where import Text.Printf (printf) import Data.List (intercalate) -- HA 3.1a) i selectRow :: [[Int]] -> Int -> [Int] selectRow xss i = xss!!i -- HA 3.1a) ii selectColumn :: [[Int]] -> Int -> [Int] selectColumn xss i = map (\n -> (n!!i)) 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] getSquareSize :: [[Int]] -> Int getSquareSize xss = intRoot (length xss) getSquareX :: [[Int]] -> Int -> Int getSquareX xss i = (i - (getSquareSize xss * (floor (fromIntegral(i) / fromIntegral (getSquareSize xss))))) * (getSquareSize xss) getSquareY :: [[Int]] -> Int -> Int getSquareY xss i = (floor (fromIntegral(i) / fromIntegral (getSquareSize xss))) * (getSquareSize xss) selectSquare :: [[Int]] -> Int -> [Int] selectSquare xss i = concat (map (\n -> take (getSquareSize xss) (drop (getSquareX xss i) (selectRow xss ((getSquareY xss i) + n)))) [0..((getSquareSize xss) - 1)]) -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xss = length (filter (\b -> b) (map (\n -> (length (filter (\x -> x == n) xss)) > 1) [1..(length xss)])) == 0 isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and (map (\i -> isValidSubsection(selectRow xss i) && isValidSubsection(selectColumn xss i) && isValidSubsection(selectSquare xss i)) [0..((length xss) - 1)]) -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell xss (j, k) x = map (\n -> if (n == j) then map (\m -> if (m == k) then x else (xss!!n)!!m) [0..((length xss) - 1)] else selectRow xss n) [0..((length xss) - 1)] -- HA 3.1d) {-WETT-} getSquareID :: [[Int]] -> (Int,Int) -> Int getSquareID xss (j, k) = (floor (fromIntegral(j) / fromIntegral (getSquareSize xss))) * ((length xss) `div` (getSquareSize xss)) + (floor (fromIntegral(k) / fromIntegral (getSquareSize xss))) freeFieldNumbers :: [[Int]] -> (Int,Int) -> [Int] freeFieldNumbers xss (j, k) = filter (\n -> n `notElem` (concat [(selectRow xss j),(selectColumn xss k),(selectSquare xss (getSquareID xss (j, k)))])) [1..(length xss)] nextFreeFieldNumber :: [[Int]] -> (Int,Int) -> Int nextFreeFieldNumber xss (j, k) = head (map (\e -> filter (\n -> length (filter (\c -> n `elem` c) (map (\f -> freeFieldNumbers xss f) (e))) == minimum (map (\n -> length (filter (\c -> n `elem` c) (map (\f -> freeFieldNumbers xss f) (e)))) (freeFieldNumbers xss (j, k)))) (freeFieldNumbers xss (j, k))) [(getEmptyFields xss)])!!0 getEmptyFields :: [[Int]] -> [(Int,Int)] getEmptyFields xss = concat (map (\r -> map (\c -> (r,c)) (filter (\n -> (selectRow xss r)!!n == 0) [0..((length xss) - 1)])) (filter (\n -> 0 `elem` xss!!n) [0..((length xss) - 1)])) nextEmptyField :: [[Int]] -> (Int,Int) nextEmptyField xss = head (map (\e -> filter (\n -> length (freeFieldNumbers xss n) == minimum (map (\f -> length (freeFieldNumbers xss f)) (e))) (e)) [(getEmptyFields xss)])!!0 solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss = if not (isValidSudoku xss) then [] else if (and (map (\n -> n /= 0) (concat xss))) then xss else if length (freeFieldNumbers xss (nextEmptyField xss)) == 0 then [] else solveSudoku (setCell xss (nextEmptyField xss) (nextFreeFieldNumber xss (nextEmptyField 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)