module Exercise03 where import Text.Printf (printf) import Data.List (intercalate, sort) -- 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 = [ xss !! a !! b | a <- [ri .. ri+size-1], b <- [ci .. ci+size-1]] where ri = i `div` size * size ci = i `mod` size * size size = intRoot $ length xss -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = isValidHelper (sort xs) [1 .. 9] isValidHelper :: [Int] -> [Int] -> Bool isValidHelper [] _ = True isValidHelper (0:xs) available = isValidHelper xs available isValidHelper _ [] = False isValidHelper (x:xs) available = let nL = [a | a <- available , a >= x] in ((x == head nL) && isValidHelper xs [a | a <- nL, a > x]) isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and [isValidSubsection (selectSquare xss i) && isValidSubsection (selectColumn xss i) && isValidSubsection (selectRow xss i) | i <- [0..length xss - 1]] -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell xss (j, k) x = [if a==j then [if b==k then x else xss !! a !! b | b <- [0.. length xss - 1]] else xss !! a| a <- [0 .. length xss - 1]] -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss | blank == (-1,-1) = if isValidSudoku xss then xss else [] | isValidSudoku xss = tryAllPossibleForCell xss blank 1 len -- recursive call | otherwise = [] where blank = findBlank xss len = 1+ length xss tryAllPossibleForCell :: [[Int]] -> (Int, Int) -> Int -> Int -> [[Int]] tryAllPossibleForCell xss blank x maxX | x == maxX = [] | otherwise = let retSod = solveSudoku (setCell xss blank x) in if null retSod then tryAllPossibleForCell xss blank (x+1) maxX else retSod findBlank :: [[Int]] -> (Int,Int) findBlank xss | null blanks = (-1,-1) | otherwise = head blanks where len = length xss - 1 blanks = [(x,y) | x <- [0 .. len], y <- [0 .. len], xss !! x !! y == 0] {-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]] solvedSudoku :: [[Int]] solvedSudoku = [[8,9,6,7,5,2,4,1,3], [5,2,3,6,1,4,9,8,7], [4,7,1,8,9,3,2,6,5], [9,5,4,3,6,7,8,2,1], [3,1,8,2,4,5,7,9,6], [7,6,2,1,8,9,5,3,4], [6,8,9,5,7,1,3,4,2], [2,4,7,9,3,6,1,5,8], [1,3,5,4,2,8,6,7,9]] easySudoku :: [[Int]] easySudoku = [[8,9,6,7,5,2,4,1,3], [5,2,3,6,1,4,9,8,7], [0,0,0,0,0,0,0,0,0], [9,5,4,3,6,7,8,2,1], [3,1,8,2,4,5,7,9,6], [7,6,2,1,8,9,5,3,4], [6,8,9,5,7,1,3,4,2], [2,4,7,9,3,6,1,5,8], [1,3,5,4,2,8,6,7,9]] -- 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)