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 = [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 r = intRoot $ length xss yIndex = i `div` r yStart = yIndex * r xStart = (i - r * yIndex) * r in concat [take r (drop xStart xs) | xs <- take r (drop yStart xss)] -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection xs = length filt == length (nub filt) where filt = filter (/=0) xs isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and ([isValidSubsection (selectRow xss y) | y <- [0..(length xss - 1)]] ++ [isValidSubsection (selectColumn xss y) | y <- [0..(length xss - 1)]] ++ [isValidSubsection (selectSquare xss y) | y <- [0..(length xss - 1)]]) -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell xss (j, k) x = take j xss ++ [take k (xss !! j) ++ [x] ++ drop (k + 1) (xss !! j)] ++ drop (j + 1) xss -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku xss = if snd sol then fst sol else [] where sol = sudIter xss (0,0) sudIter :: [[Int]] -> (Int, Int) -> ([[Int]], Bool) sudIter xss (x,y) | sudokuFinished xss (x,y) = (xss, True) | otherwise = if sudokuNull xss (x,y) then itOneToN xss [1..(length xss)] (x,y) else (if y < (length xss - 1) then sudIter xss (x, y + 1) else sudIter xss (x + 1, 0)) itOneToN :: [[Int]] -> [Int] -> (Int, Int) -> ([[Int]], Bool) itOneToN xss [] _ = (xss, False) itOneToN xss (y:ys) (a,b) = let newBoard = setCell xss (a,b) y sudNew = sudIter newBoard (0,0) in if isValidSudoku newBoard && snd sudNew then sudNew else itOneToN xss ys (a,b) sudokuCell :: [[Int]] -> (Int, Int) -> Int sudokuCell xss (x,y) = xss !! x !! y sudokuNull :: [[Int]] -> (Int, Int) -> Bool sudokuNull xss (x,y) = xss !! x !! y == 0 sudokuFinished :: [[Int]] -> (Int, Int) -> Bool sudokuFinished xss (x, y) = x == length xss && y == 0 {-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)