{-# language ScopedTypeVariables #-} import Prelude hiding ( not ) import qualified Prelude import Satchmo.Relation import Satchmo.Code import Satchmo.Boolean import Satchmo.Counting import Satchmo.Solver.Minisat import Data.List (sort) import qualified Data.Array as A import Control.Monad ( guard, when, forM ) import System.Environment import Data.Ix ( range) -- | command line arguments: m n -- compute knight's tour on m x n chess board main :: IO () main = do argv <- getArgs let [ m, n ] = map read argv Just a <- solve $ tour m n putStrLn $ unlines $ do let ((u,l),(o,r)) = A.bounds a x <- [u .. o] return $ unwords $ do y <- [ l ..r ] return $ fill 4 $ show $ a A.! (x,y) fill k cs = replicate (k - length cs) ' ' ++ cs tour m n = do let s = m * n felder = range ((1,1),(m,n)) p :: Relation Int (Int,Int) <- bijection ((1,(1,1)), (s,(m,n))) forM ( zip [1..s] $ rotate 1 [1..s] ) $ \ (i,i') -> do forM felder $ \ j -> assert $ not ( p!(i,j)) : do k <- felder guard $ reaches j k return $ p ! (i',k) forM felder $ \ k -> assert $ not ( p!(i',k)) : do j <- felder guard $ reaches j k return $ p ! (i,j) {- forM felder $ \ j -> forM felder $ \ k -> do c <- constant $ reaches j k assert [ not $ p!(i,j), not $ p!(i',k) , c ] -} return $ do a <- decode p return $ A.array ((1,1),(m,n)) $ do ((i,p),True) <- A.assocs a return (p,i) bijection :: (A.Ix a, A.Ix b) => ((a,b),(a,b)) -> SAT ( Relation a b ) bijection bnd = do let ((u,l),(o,r)) = bnd a <- relation bnd -- official encoding: exactly one per row, exactly one per column sequence_ $ do x <- A.range (u,o) return $ monadic assert $ return $ exactly 1 $ do y <- A.range (l,r) ; return $ a!(x,y) sequence_ $ do y <- A.range (l,r) return $ monadic assert $ return $ exactly 1 $ do x <- A.range (u,o) ; return $ a!(x,y) {- -- this should be enough: at least one per row, at most one per column sequence_ $ do x <- A.range (u,o) return $ assert $ do y <- A.range (l,r) ; return $ a!(x,y) sequence_ $ do y <- A.range (l,r) return $ monadic assert $ return $ atmost 1 $ do x <- A.range (u,o) ; return $ a!(x,y) -} return a reaches (px,py) (qx,qy) = 5 == (px - qx)^2 + (py - qy)^2 rotate :: Int -> [a] -> [a] rotate k xs = let ( pre, post ) = splitAt k xs in post ++ pre