satchmo-2.9.9.3: examples/Sudoku.hs
-- | Simple Sudoku Benchmark:
-- constraints for an empty board (no hints).
-- argument n: board is (n^2)x(n^2),
-- so standard Sudoku is for n=3
{-# language PatternSignatures #-}
import Prelude hiding ( not, product )
import qualified Prelude
import qualified Satchmo.Relation as R
import Satchmo.Code
import Satchmo.Boolean
import Satchmo.SAT.Mini
import Data.List (inits, tails)
import qualified Data.Array as A
import Control.Monad ( guard, when, forM, foldM, forM_ )
import System.Environment
import Data.Ix ( range)
main :: IO ()
main = do
argv <- getArgs
case argv of
[ ] -> main_with 5
[s] -> main_with $ read s
main_with :: Int -> IO ()
main_with n = do
Just r <- solve $ sudoku n
printA n r
printA :: Int -> A.Array ((Int,Int,Int,Int),(Int,Int)) Bool -> IO ()
printA n a = putStrLn $ unlines $ do
(x1,x2) <- A.range ((1,1),(n,n))
return $ unwords $ do
(y1,y2) <- A.range ((1,1),(n,n))
let zs = map (\z -> a A.! ((x1,x2,y1,y2),z) ) (A.range ((1,1),(n,n)) )
fill n s = replicate (n - length s) ' ' ++ s
return $ fill 3 $ show $ length $ takeWhile Prelude.not zs
sudoku :: Int
-> SAT (SAT (A.Array ((Int,Int,Int,Int),(Int,Int)) Bool))
sudoku n = do
r :: R.Relation (Int,Int,Int,Int) (Int,Int) <-
R.relation (((1,1,1,1),(1,1)),((n,n,n,n),(n,n)))
forM_ [ blockA, blockB, blockC ] $ \ bl ->
forM_ (A.range ((1,1),(n,n))) $ \ (x,y) ->
assertM $ R.is_bijection $ bl n r (x,y)
return $ decode r
blockA (n::Int) r (x,y) =
fromfunc (((1,1),(1,1)),((n,n),(n,n)))
$ \ ((x1,x2),(y1,y2)) -> r R.! ((x,y,x1,x2),(y1,y2))
blockB (n::Int) r (x,y) =
fromfunc (((1,1),(1,1)),((n,n),(n,n)))
$ \ ((x1,x2),(y1,y2)) -> r R.! ((x1,x2,x,y),(y1,y2))
blockC (n::Int) r (x,y) =
fromfunc (((1,1),(1,1)),((n,n),(n,n)))
$ \ ((x1,x2),(y1,y2)) -> r R.! ((x,x1,y,x2),(y1,y2))
assertM action = do x <- action ; assert [x]
fromfunc bnd f = R.build bnd $ do i <- A.range bnd ; return (i, f i )