module Exercise03 where import Text.Printf (printf) import Data.List (intercalate) -- 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 = [fst x | xs <- xss `zip` [0..n-1], (i `div` k)*k <= snd xs, snd xs < (i `div` k + 1) * k, x <- fst xs `zip` [0..n-1], (i `mod` k)*k <= snd x, snd x < (i `mod` k + 1) * k] where n = length xss k = intRoot n -- HA 3.1b) isValidSubsection :: [Int] -> Bool isValidSubsection [] = True isValidSubsection (x:xs) = (x == 0 || x `notElem` xs) && isValidSubsection xs isValidSudoku :: [[Int]] -> Bool isValidSudoku xss = and (boolListValidSubsections selectRow ++ boolListValidSubsections selectColumn ++ boolListValidSubsections selectSquare) where boolListValidSubsections selectFunction = [isValidSubsection (selectFunction xss i) | i <- [0..length xss - 1]] -- HA 3.1c) setCell :: [[Int]] -> (Int,Int) -> Int -> [[Int]] setCell ((_:xs):xss) (0,0) n = (n:xs):xss setCell (xs:xss) (0,j) n = setCellInList xs j n:xss setCell (xs:xss) (k, j) n = xs:setCell xss (k-1,j) n setCellInList :: [Int] -> Int -> Int -> [Int] setCellInList (_:xs) 0 n = n:xs setCellInList (x:xs) j n = x:setCellInList xs (j-1) n -- HA 3.1d) {-WETT-} solveSudoku :: [[Int]] -> [[Int]] solveSudoku sudoku = addNumber sudoku (0,0) (0,0) 1 1 addNumber :: [[Int]] -> (Int,Int) -> (Int,Int) -> Int -> Int -> [[Int]] addNumber sudoku (x,y) (lastX,lastY) value count | count > n = [] | not (isValidSudokuModified sudoku (lastX,lastY)) = [] | y >= n = sudoku | sudoku !! x !! y /= 0 = addNumber sudoku (nextCell (x,y) n) (x,y) value 1 | otherwise = if recursion /= [] then recursion else addNumber sudoku (x,y) (x,y) (value `mod` n + 1) (count + 1) where recursion = addNumber (setCell sudoku (x,y) value) (nextCell (x,y) n) (x,y) (value `mod` n + 1) 1 n = length sudoku isValidSudokuModified :: [[Int]] -> (Int,Int) -> Bool isValidSudokuModified sudoku (x,y) = isValidSubsection (selectRow sudoku x) && isValidSubsection (selectColumn sudoku y) && isValidSubsection (selectSquare sudoku ((x `div` k)*k+(y `div` k))) where k = intRoot $ length sudoku nextCell :: (Int,Int) -> Int -> (Int,Int) nextCell (x,y) n | x + 1 < n = (x+1,y) | otherwise = (0,y+1) {-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]] easySudoku :: [[Int]] easySudoku = [[9,3,0,0,0,7,2,0,8], [5,4,0,1,0,0,0,6,0], [6,7,0,0,3,2,4,0,0], [0,8,0,0,0,5,1,7,0], [7,5,0,3,0,1,0,9,2], [0,0,0,0,0,0,0,3,0], [4,0,0,8,0,3,5,0,0], [0,0,0,2,0,0,0,0,0], [1,2,0,7,6,0,9,8,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)