module Exercise03 where import Text.Printf (printf) import Data.List import Data.Maybe -- HA 3.1a) i selectRow :: [[Int]] -> Int -> [Int] selectRow xss i = xss !! i -- HA 3.1a) ii selectColumn :: [[Int]] -> Int -> [Int] selectColumn xss i = transpose xss !! i -- 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 !! y !! x | y <- [startY..endY], x <- [startX..endX]] where size = length xss root = intRoot size startX = root * (i `mod` root) endX = startX + root - 1 startY = root * (i `div` root) endY = startY + root - 1 -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = let filtered = filter (0/=) xs in length filtered == length (nub filtered) isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and [isValidSubsection (selectRow xss i) && isValidSubsection (selectColumn xss i) && isValidSubsection (selectSquare xss i) | i <- [0..length xss - 1]] -- HA 3.1c) setCellinRow :: [Int] -> Int -> Int -> [Int] setCellinRow (_:xs) 0 x = x : xs setCellinRow (y:xs) i x = y : setCellinRow xs (i - 1) x setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell (ys:xss) (0, k) x = setCellinRow ys k x : xss setCell (ys:xss) (j, k) x = ys : setCell xss (j - 1, k) x -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss = helper xss $ writableCells xss where size = length xss getRow i = i `div` size getColumn i = i `mod` size coords i = (getRow i, getColumn i) withCell xss i x = setCell xss (coords i) x writableCells :: [[Int]] -> [Int] writableCells xss = [i | (i, x) <- zip [0..size^2 - 1] (concat xss), x == 0] options :: [[Int]] -> (Int, Int) -> [Int] options xss (y, x) = (([1..size] \\ selectRow xss y) \\ selectColumn xss x) \\ selectSquare xss squareNum where root = intRoot size squareNum = (x `div` root) + (y `div` root) * root helper :: [[Int]] -> [Int] -> [[Int]] helper xss [] = if isValidSudoku xss then xss else [] helper xss (i:ys) = fromMaybe [] (find (/=[]) [helper (withCell xss i x) ys | x <- options xss (coords i)]) {-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)