module Exercise03 where import Text.Printf (printf) import Data.List (intercalate) import Data.List (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 = [xs !! y | xs <- take root (drop (root*pos) xss), y <- [mod i root*root .. (mod i root*root)+root-1]] where root = intRoot (length xss) pos = div i root -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = all (==True) [uncurry (<) z && fst z <= length xs && snd z <= length xs | z <- [(ys !! i, ys !! (i+1)) | i <- [0 .. length ys-2]]] where ys = sort [x | x <- xs, x /= 0] isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = all (==True) [all (==True) ([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 (j, k) x = [[if l==j && i==k then x else x2 |(x2,i) <- zip xs [0 .. length xss-1]]| (xs,l) <- zip xss [0 .. length xss-1]] -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss = solveSudoku1 xss 0 0 xss 1 findNextLegal :: [[Int]] -> Int -> Int -> Int -> Int -- finds next legal number higher then z at pos x y findNextLegal xss z x y | z >= length xss || z<0 = - 1 | isValidSudoku (setCell xss (y, x) (z+1)) = z+1 | otherwise = findNextLegal xss (z+1) x y solveSudoku1 :: [[Int]] -> Int -> Int -> [[Int]] -> Int -> [[Int]] solveSudoku1 xss x (-1) yss i= [] solveSudoku1 xss x (-2) yss i= xss solveSudoku1 xss x y yss i | yss!!y!!x/=0 = solveSudoku1 xss (mod (x+i) (length xss)) (if x+i<0 || x+i>=length xss then (if y+i>=length xss then -2 else y+i) else y) yss i | next == -1 = solveSudoku1 (setCell xss (y,x) 0) (mod (x-1) (length xss)) (if x-1<0 then y-1 else y) yss (-1) | otherwise = solveSudoku1 (setCell xss (y,x) next) (mod (x+1) (length xss)) (if x+1>=length xss then (if y+1>=length xss then -2 else y+1) else y) yss 1 where next = findNextLegal xss (xss!!y!!x) x y {-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)