Monday, December 6, 2010

A Imperative Style Haskell Sudoku Solver

Here is the Haskell equivalent of the Sudoku solver in C. I tried to do a line-by-line translation from C to Haskell. I hope the program shows that Haskell is a better imperative language than the imperative languages :-)


import List
import Array
import Control.Monad.State

strToArray :: String -> Array (Int, Int) Int
strToArray s = array ((0,0), (8,8)) $ zip [(m,n) | m <- [0 .. 8], n <- [0 ..8]] $
map read (concat (map words $ lines s))

display :: Array (Int, Int) Int -> IO()
display grid = do {
forM_ [0..8] $ \m -> do {
forM_ [0..8] $ \n -> do {
putStr $ show (grid!(m, n)) ++ " ";
};
putStrLn "";
};
putStrLn "";
}

solve :: Int->Int->StateT (Array (Int, Int) Int) IO ()
solve x y = do {
grid <- get;
if grid!(x,y) /= 0 then
if (x == 8) && ( y == 8) then
lift (display grid)
else
solve ((x+1) `mod` 9) (if x == 8 then (y+1) else y)
else
do {
forM_ [1..9] $ \c -> do {
if (verify grid x y c) then
put (grid //[((x,y),c)]) >> solve x y
else
return ()
};
put (grid //[((x,y),0)]);
}
}

main :: IO ()
main = do {
s <- getContents;
evalStateT (solve 0 0) (strToArray s);
}

loopUntil :: [Int]->(Int->Bool)->Bool
loopUntil s f =
case s of
x:xs -> if (f x) then (loopUntil xs f) else False
[] -> True

verify1 :: Array (Int, Int) Int -> Int -> Int -> Int -> Bool
verify1 grid x y c = loopUntil [0 .. 8] $ \i ->
not (grid!(i,y) == c || grid!(x,i) == c)

verify2 :: Array (Int, Int) Int -> Int -> Int -> Int -> Bool
verify2 grid x y c =
let { xs = (x `quot` 3)*3} in
let { ys = (y `quot` 3)*3} in
loopUntil [xs .. xs+2] $ \i ->
loopUntil [ys .. ys+2] $ \j -> not (grid!(i,j) == c)

verify :: Array (Int, Int) Int -> Int -> Int -> Int -> Bool
verify grid x y c = (verify1 grid x y c) && (verify2 grid x y c)

No comments: