packages feed

satchmo-2.9.7.3: examples/Spaceship.hs

-- | compute spaceship for Conway's game of life, 
-- cf. http://www.conwaylife.com/wiki/Category:Oscillators
-- arguments are: distanceX, distanceY, exact period
-- width [, height, [number of life start cells]]
-- example usage: 
-- ./Spaceship 1 1 4 6     -- glider
-- ./Spaceship 0 2 4 7 9 9 -- Conway's lightweight spaceship

{-# language PatternSignatures #-}
{-# language FlexibleContexts #-}

import Prelude hiding ( not, or, and )
import qualified Prelude

import Satchmo.Relation
import Satchmo.Code
import Satchmo.Boolean hiding ( equals, implies )
import qualified Satchmo.Binary as B

import qualified Satchmo.Counting.Direct as CD
import qualified Satchmo.Counting.Unary as CU
import qualified Satchmo.Counting.Binary as CB

import Satchmo.SAT.Mini

import Data.List (sort)
import qualified Data.Array as A
import Control.Monad ( guard, when, forM, foldM
  , void, replicateM )
import System.Environment
import Data.Ix ( range, inRange )

main :: IO ()
main = void $ do
    argv <- getArgs
    Just gs <- case map read argv of
        [] ->
          solve $ glide 0  2  4 7 9 (Just 9)
        [ dx, dy, p, w       ] ->
          solve $ glide dx dy p w w Nothing
        [ dx, dy, p, w, h    ] ->
          solve $ glide dx dy p w h Nothing
        [ dx, dy, p, w, h, c ] ->
          solve $ glide dx dy p w h $ Just c
    forM ( zip [ 0..  ] gs ) $ \ (t, g) -> do
        putStrLn $ unwords [ "time", show t ]
        printA g

printA :: A.Array (Int,Int) Bool -> IO ()
printA a = putStrLn $ unlines $ do
         let ((u,l),(o,r)) = A.bounds a
         x <- [u .. o]
         return $ unwords $ do 
             y <- [ l ..r ]
             return $ case a A.! (x,y) of
                  True -> "* " ; False -> ". "

for = flip map

glide :: Int -> Int -> Int -> Int -> Int -> Maybe Int
      -> SAT ( SAT [A.Array (Int,Int) Bool] )
glide dx dy p w h mc = do
    g0 <- relation ((1,1),(w,h))
    assert $ map snd $ assocs g0
    case mc of
         Just c -> monadic assert [ CB.atmost c $ map snd $ assocs g0 ]
         Nothing -> return ()
    let handle 0 g = return [g]
        handle k g = do g' <- next g ; gs <- handle (k-1) g' ; return $ g : gs
    gs <- handle p g0 
    forM gs bordered

    -- ms <- forM ( tail gs ) $ \ h -> moved (dx,dy) ( head gs ) h
    -- assert $ ms
    m <- moved (dx,dy) (head gs) (last gs)
    assert [m]

    return $ decode gs

equals r s = monadic and [ implies r s, implies s r ]

moved (dx,dy) g h = do
    f <- constant False
    let bnd @ ((l,o),(r,u)) = bounds g
        get g p = if inRange bnd p then g ! p else f
    monadic and $ for ( range bnd ) $ \ (x,y) -> do
        fun2 (==) ( get g (x,y) ) ( get h (x+dx, y+dy) )


bordered g = do
    let ((u,l),(d,r)) = bounds g
    forM [ u .. d ] $ \ x -> forM [ l  , r ] $ \ y -> assert [ not $ g!(x,y) ]
    forM [ u ,  d ] $ \ x -> forM [ l .. r ] $ \ y -> assert [ not $ g!(x,y) ]


next g = do
    f <- constant False
    let bnd = bounds g
    let neighbours (i,j) = do
            i' <- [ i-1, i, i+1 ]
            j' <- [ j-1, j, j+1 ]
            guard $ i /= i' Prelude.|| j /= j'
            return $ if inRange bnd (i',j') 
               then g ! (i', j')
               else f
    pairs <- forM ( assocs g ) $ \ (p, x) -> do
        y <- step x $ neighbours p
        return (p, y)
    return $ build bnd pairs

step = step_mod

step_mod x xs = do
  c <- CB.count xs
  drei <- B.constant 3
  birth <- B.equals drei c
  zwei <- B.constant 2
  keep <- B.equals zwei c
  keepx <- and [keep, x]
  or [ keepx, birth ]

step_orig x xs = do
    cs <- counts 3 xs
    keep <- and [ x, cs !! 2 ]
    let birth = cs !! 3
    or [ keep, birth ]

-- | output !! k  == True
-- if exactly  k  of the inputs are True
counts :: MonadSAT m
       => Int -> [ Boolean ] 
       -> m [ Boolean ]
counts w xs = do
    t <- constant True ; f <- constant False
    let handle cs x = do
           ds <- forM cs $ \ c -> boolean
           forM ( zip cs ds ) $ \ (c,d) -> do
               assert_fun3 ( \ c d x -> Prelude.not x <= ( c == d ) ) c d x
           forM ( zip ( f : cs) ds ) $ \ (c,d) -> do
               assert_fun3 ( \ c d x -> x <= ( c == d ) ) c d x
           return ds
    foldM handle ( t : replicate w f ) xs