import Data.Bits (shift)
import Data.List (unfoldr)
import Control.Arrow ((***))
import Control.Monad (when, join)
import Data.Set (insert, delete, member, empty, fromList, toList)
import Graphics.UI.SDL as SDL
import System.Random.Mersenne.Pure64 (newPureMT, randomInt)
(xres, yres, sq, cast) = (1600, 900, 3, fromIntegral)
origin = (xres `div` 2 `div` sq, yres `div` 2 `div` sq)
main = withInit [InitVideo] $ do
w <- setVideoMode xres yres 32 [NoFrame]
enableEvent SDLMouseMotion False
setCaption "Langton's Ant" "Langton's Ant"
pause w origin (0,1) empty
pause w p v ps = do
delay 128
e <- pollEvent
case e of
KeyUp (Keysym SDLK_ESCAPE _ _) -> return ()
KeyUp (Keysym SDLK_SPACE _ _) -> run w [1..] p v ps
KeyUp (Keysym SDLK_r _ _) -> randomize
_ -> pause w p v ps
where
randomize = do
ps <- randPattern
render w ps
pause w origin (0,1) ps
run w (n:ns) p v ps = do
when (n `mod` 7 == 0) $ render w ps
e <- pollEvent
case e of
KeyUp (Keysym SDLK_ESCAPE _ _) -> print n
KeyUp (Keysym SDLK_SPACE _ _) -> pause w p v ps
_ -> continue
where
continue = run w ns (move p $ g v) (g v) $ f p ps
b = member p ps
f = if b then delete else insert
g = if b then fl else fr
move (x,y) = (x+) *** (+y)
fr (x,y) = if x == 0 then (-y,x) else (y,x)
fl (x,y) = if x == 0 then (y,x) else (y,-x)
render w ps = do
fillRect w (Just $ Rect 0 0 xres yres) $ Pixel 0
mapM_ (draw w . join (***) (* sq)) $ toList ps
SDL.flip w
draw w p = f p =<< g [SWSurface] sq sq 32 0 0 0 0
where
rect x y = Just $ Rect x y sq sq
g = createRGBSurface
f (x,y) s = do fillRect s (rect 0 0) $ Pixel $ rgb x y
blitSurface s (rect 0 0) w $ rect x y
randPattern = fmap (fromList . f) newPureMT
where
f = center . uncurry zip . splitAt 11000 . g
g = map (`rem` 512) . unfoldr (Just . randomInt)
center = map $ (x+) *** (+y)
where
[x,y] = map (`div` (2 * sq)) [xres, yres]
rgb x y = shift r 16 + shift g 8 + 128
where
r = round $ (cast x / cast xres) * 255
g = round $ (cast y / cast yres) * 255
Tuesday, October 6, 2009
plenary ant
Here's a more polished edition of the basic Langton's ant previously posted. As in this version of Conway's Life, you can pause with the space key, and press r while paused to restart with a random pattern. Just for fun I also threw in colors.
On exiting, the code prints the iteration count - given populous initial states, it's interesting how much this value can vary before the ant builds its inevitable highway.
Labels:
cellular automata,
chaos,
computational universality
Subscribe to:
Comments (Atom)