module Exercise03 where import Data.List (intercalate) 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 l = intRoot (length xss) ris = [l * (i `div` l) + x | x <- [0 .. (l - 1)]] --ris ist eine Liste, die alle Zeilenindices enthält cis = [l * (i `mod` l) + x | x <- [0 .. (l - 1)]] --cis ist eine Liste, die alle Spaltenindices enthält in [r' !! c | r' <- [selectRow xss r | r <- ris], c <- cis] --rows -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection [_] = True isValidSubsection (x : xs) | x == 0 || null [x | x' <- xs, x == x'] = isValidSubsection xs | otherwise = False isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = let is = [0 .. (length xss - 1)] in and [isValidSubsection (selectRow xss i) | i <- is] --rows && and [isValidSubsection (selectColumn xss i) | i <- is] --columns && and [isValidSubsection (selectSquare xss i) | i <- is] --squares -- HA 3.1c) --careful: => not intuitive setCell :: [[Int]] -> (Int, Int) -> Int -> [[Int]] setCell xss (r, c) x = replace xss r (replace (selectRow xss r) c x) replace :: [a] -> Int -> a -> [a] replace xs i n = let (xs1, _ : xs2) = splitAt i xs in xs1 ++ [n] ++ xs2 -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss | isValidSudoku xss = solve xss ni (getValidNumbers xss (indexToTuple ni (length xss))) | otherwise = [] where ni = next0Index xss 0 solve :: [[Int]] -> Int -> [Int] -> [[Int]] solve xss (-1) _ = xss solve _ _ [] = [] solve xss i (vn : vns) = let ni = next0Index xss (i + 1) l = length xss scxss = setCell xss (indexToTuple i l) vn sxss = solve scxss ni (getValidNumbers scxss (indexToTuple ni l)) in if null sxss then solve xss i vns else sxss indexToTuple :: Int -> Int -> (Int, Int) indexToTuple (-1) _ = (0, 0) indexToTuple i l = (div i l, mod i l) next0Index :: [[Int]] -> Int -> Int next0Index xss i | i == (length xss ^ 2) = -1 | x /= 0 = next0Index xss (i + 1) | otherwise = i where (r, c) = indexToTuple i (length xss) x = selectRow xss r !! c getValidNumbers :: [[Int]] -> (Int, Int) -> [Int] getValidNumbers xss (r, c) = let l = intRoot (length xss) crs = selectColumn xss c ++ selectRow xss r ++ selectSquare xss (div c l + div r l * l) in [i | i <- [1 .. length xss], i `notElem` crs] {-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] ] smallSudoku :: [[Int]] smallSudoku = [ [0, 0, 0, 0], [3, 3, 0, 0], [3, 0, 2, 0], [0, 0, 0, 0] ] smallSudoku1 :: [[Int]] smallSudoku1 = [ [3, 0, 0, 0], [0, 0, 2, 0], [0, 1, 0, 0], [0, 0, 0, 2] ] tinySudoku :: [[Int]] tinySudoku = [[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)