module Exercise03 where import Text.Printf (printf) import Data.List (intercalate) -- HA 3.1a) i selectRow :: [[Int]] -> Int -> [Int] selectRow [] _ = []; selectRow xss i = xss !! i; -- HA 3.1a) ii selectColumn :: [[Int]] -> Int -> [Int] selectColumn [] _ = []; 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 [] _ = [] selectSquare xss i = [xss !! j !! k | j <-[spK .. (spK+s-1)], k <- [zeK .. (zeK+s-1)]] where s = intRoot (length xss) -- Sudokogroesse spK = div i s * s -- spaltennummer in der Feld beginnt (0...n) zeK = mod i s * s -- zeilennummer in der Feld beginnt (0...n) -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection [] = True isValidSubsection (x:xs) | null xs = True | x == 0 = isValidSubsection xs | otherwise = and [x /= y | y <- xs] && isValidSubsection xs isValidSudoku :: [[Int]] -> Bool isValidSudoku [] = True isValidSudoku xss = and [isValidSubsection(selectRow xss i) && isValidSubsection(selectColumn xss i) && isValidSubsection(selectSquare xss i)| i <- [0 .. (length xss-1)]] -- other posibility: isValidSudoku xss = and[isValidKod xss (a,b)| a <- [0 .. (length xss-1)], b <- [0 .. (length xss -1)]] -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell xss (j, k) x = [if u == j then [if t == k then x else xss !! u !! t | t <- xc] else xss !! u |u <- xc] where xc = [0 .. (length xss-1)] -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss | xss == [[]] = xss |not(isValidSudoku xss) = [] | otherwise = let (l,b) = solveSudokuKord xss (0,0) in if b then l else [] solveSudokuKord :: [[Int]] -> (Int, Int) -> ([[Int]], Bool) solveSudokuKord xss (a,b) | a == -1 = (xss, True) -- geloest | xss !! a !! b /= 0 = solveSudokuKord xss (getNextKord xss (a,b)) | otherwise = walkSudokuKord (setCell xss (a,b) 1) (a,b) -- läuft durch mögliche Werte des Sudokus an der stelle (a,b) vor Methode ist c schon in (a,b) gesetzt walkSudokuKord :: [[Int]] -> (Int, Int) -> ([[Int]], Bool) walkSudokuKord xss (a,b) --Koordinaten -1 bei erfolgreichem Entschluesseln | (a,b) == (-1,-1) = (xss, True) --Passt keine der Koordinaten [1 .. length], gebe Falsch zurueck | c == length xss + 1 = ([], False) -- sudoku in dieser Kombi nicht machbar | v = let (s,t) = solveSudokuKord xss (getNextKord xss (a,b)) in --funktioniert dies möglichkeit suche nach einer Möglichkeit zum gesamten lösen if t then (s,t) --gibt es eine Möglichkeit gebe sie zurueck else walkSudokuKord (setCell xss (a,b) (c+1)) (a,b) -- sonst probiere nächsten wert für dieses Feld aus |otherwise = walkSudokuKord (setCell xss(a,b) (c+1)) (a,b) --probiere nächsten wert where c = xss !! a !! b v = isValidKod xss (a,b) getNextKord :: [[Int]] -> (Int, Int) -> (Int, Int) getNextKord xss (a,b) | a /= length xss - 1 = (a+1, b) | b /= length xss - 1 = (0, b+1) | otherwise = (-1, -1) --prueft ob neue Koordinate valide ist !!!Funktioniert noch nicht richtig isValidKod :: [[Int]] -> (Int, Int) -> Bool isValidKod xss (a,b) = isValidSubsection (selectRow xss a) && isValidSubsection (selectColumn xss b) && isValidSubsection (selectSquare xss (div a h + (div b h * h))) where h = intRoot(length xss) {-TTEW-} hardSuSm ::[[Int]] hardSuSm = [[1,0,2,0], [0,0,1,0], [0,2,3,0], [0,0,0,0]] 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 _ [] = [] chunksOf i ls = take i ls : chunksOf i (drop i ls)