[Haskell-cafe] Norvig's Sudoku Solver in Haskell
Chaddaï Fouché
chaddai.fouche at gmail.com
Mon Aug 27 11:13:16 EDT 2007
For the translation of the above OCaml code, there is not much to do,
in fact it is mostly functional, and so easily translated in Haskell
code, note that I add a code to handle input of the form
"4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......",
to resolve it and print a solution :
<haskell>
import Data.Ix
import Data.List
import Data.Char
import qualified Data.Map as M
invalid :: (Int, Int) -> (Int, Int) -> Bool
invalid (i, j) (i', j') = i==i' || j==j' ||
(i `div` 3 == i' `div` 3 && j `div` 3 == j' `div` 3)
select p n p' ns = if invalid p p' then filter (/= n) ns else ns
cmp (_, l1) (_, l2) = (length l1) `compare` (length l2)
add p n sols =
sortBy cmp $ map (\(p', ns) -> (p', select p n p' ns)) sols
search f sol [] = f sol
search f sol ((p, ns):sols) =
concatMap (\n -> search f (M.insert p n sol) (add p n sols)) ns
</haskell>
My additions :
<haskell>
base :: [((Int, Int),[Int])]
base = [((i,j), [1..9]) | i <- [0..8], j <- [0..8]]
createBoard input = foldr constraint (M.empty, purge base input) input
where
constraint (p, [n]) (sol,sols) = (M.insert p n sol,add p n sols)
purge b i = filter (maybe True (const False) . flip lookup i . fst) b
inputBoard :: String -> [((Int, Int), [Int])]
inputBoard = filter (not . null . snd)
. zip (range ((0,0),(8,8)))
. map (\c -> if isDigit c then [read [c]] else [])
showSol = unlines . concat . intersperse ([replicate 15 '-']) . split 3
. map (unwords . intersperse "|" . split 3) . split 9
. map (chr . (+ ord '0')) . M.elems
where
split n = takeWhile (not . null) . unfoldr (Just . splitAt n)
solve = head . uncurry (search ((:[]).showSol)) . createBoard . inputBoard
main = interact $ solve
</haskell>
--
Jedaï
More information about the Haskell-Cafe
mailing list