module Exercise03 where import Text.Printf (printf) import Data.List -- HA 3.1a) i selectRow :: [[Int]] -> Int -> [Int] selectRow xss i = xss !! i -- HA 3.1a) ii selectColumn :: [[Int]] -> Int -> [Int] selectColumn xss i = [ x !! i | x <- 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 size = intRoot (length xss) in [xss !! o !! k | o <- [(i `div` size * size) .. (i `div` size * size + size - 1)], k <- [i `mod` size * size .. i `mod` size * size + (size-1)]] -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection a = and [length (filter (i ==) a) < 2 | i <- [1 .. 9]] isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and [isValidSubsection $ selectRow xss i | i <- [0 .. length xss - 1]] && and [isValidSubsection $ selectColumn xss i | i <- [0 .. length xss - 1]] && and [isValidSubsection $ selectSquare xss i | i <- [0 .. length xss - 1]] -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell xss (j, k) x = let row = selectRow xss j (a, _:xs) = splitAt j xss in let (b, _:y) = splitAt k row in let temp = b ++ (x:y) in a ++ temp : xs -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss = helper xss helper :: [[Int]] -> [[Int]] helper xss | finder xss == (-1,-1) && isValidSudoku xss = xss | not (isValidSudoku xss) = [] | otherwise = let temp = [helper (setCell xss (finder xss) k) | k <- [1 .. (length xss)]] in if any ([] /=) temp then head (filter (/= []) temp) else [] finder :: [[Int]] -> (Int, Int) finder a = let zero = or [ 0 `elem` x | x <- a] in if zero then (findposition True [ 0 `elem` x | x <- a], findposition 0 (selectRow a (findposition True ([0 `elem` x | x <- a])))) else (-1,-1) findposition :: Eq a => a -> [a] -> Int findposition number = (\(Just i)->i) . elemIndex number {-TTEW-} {- findelem :: [[[Int]]] -> [[Int]] findelem a = (\(Just i)->i) . find (/= [[]]) a -} 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)