3 import Control.Concurrent (threadDelay)
6 import Data.Functor.Compose (Compose(..))
7 import Data.Vector (Vector, (!), generate)
8 import Data.Bool (bool)
9 import Data.Distributive (Distributive(..))
10 import Data.Functor.Rep (Representable(..), distributeRep)
11 import Data.Functor.Identity (Identity(..))
12 import Control.Comonad.Representable.Store (Store(..), StoreT(..), store, experiment)
13 import Control.Comonad (Comonad(..))
14 import Control.Monad (forM_)
16 type Coord = (Int, Int)
17 type Grid = Store (Compose Vector Vector) Bool
18 type Rule = Grid -> Bool
20 instance Distributive Vector where
21 distribute = distributeRep
23 instance Representable Vector where
25 index v i = v ! (i `mod` gridSize)
26 tabulate = generate gridSize
31 neighbourCoords :: [Coord]
32 neighbourCoords = [(x, y) | x <- [-1, 0, 1], y <- [-1, 0, 1], (x, y) /= (0, 0)]
34 addCoords :: Coord -> Coord -> Coord
35 addCoords (x, y) (x', y') = (x + x', y + y')
38 basicRule g = numNeighboursAlive == 3 || (alive && numNeighboursAlive == 2)
41 neighbours = experiment (at neighbourCoords) g
42 numNeighboursAlive = length (filter id neighbours)
44 step :: Rule -> Grid -> Grid
47 render :: Grid -> String
48 render (StoreT (Identity (Compose g)) _) = foldMap ((++ "\n") . foldMap (bool "." "#")) g
50 mkGrid :: [Coord] -> Grid
51 mkGrid xs = store (`elem` xs) (0, 0)
53 at :: [Coord] -> Coord -> [Coord]
54 coords `at` origin = map (addCoords origin) coords
56 glider, blinker, beacon :: [Coord]
57 glider = [(1, 0), (2, 1), (0, 2), (1, 2), (2, 2)]
58 blinker = [(0, 0), (1, 0), (2, 0)]
59 beacon = [(0, 0), (1, 0), (0, 1), (3, 2), (2, 3), (3, 3)]
72 ++ beacon `at` (15, 5)
75 main = forM_ (iterate (step basicRule) start) $ \grid -> do
76 putStr "\ESC[2J" -- Clear terminal screen
77 putStrLn (render grid)