Skip to content

Instantly share code, notes, and snippets.

@ret
Last active October 9, 2018 07:56
Show Gist options
  • Save ret/4217b3e0733727df99df251534381a87 to your computer and use it in GitHub Desktop.
Save ret/4217b3e0733727df99df251534381a87 to your computer and use it in GitHub Desktop.
module LEDsMojo.GameOfLife (CellT, gameOfLife) where
import qualified Data.List as L ((\\))
import Data.Sized.Matrix as M
import Data.Sized.Unsigned
import Language.KansasLava
type CellT = Bool
gameOfLife :: Matrix (X8, X16) CellT -> Signal CLK Bool -> Matrix (X8, X16) (Signal CLK CellT)
gameOfLife initBoard ena = board
where
-- structural laziness is key here - board is defined in terms of board
-- at various coordinates as we iterate through cells (coordinates)
board = forAll (\ i@(ix, iy) ->
let neighbors = net board (fromIntegral ix, fromIntegral iy)
in cell (initBoard ! i) ena neighbors)
net :: Matrix (X8, X16) (Signal CLK CellT) -> (Int, Int) -> Matrix X8 (Maybe (Signal CLK CellT))
net mat (ix,iy) = M.fromList $ map maybeE ixList
where
ixList :: [(Int, Int)]
ixList = [ (ix + dx, iy + dy) | dx <- [-1,0,1], dy <- [-1,0,1] ] L.\\ [(ix,iy)]
maybeE :: (Int, Int) -> Maybe (Signal CLK CellT)
maybeE (-1, _) = Nothing
maybeE ( _, -1) = Nothing
maybeE ( 8, _) = Nothing
maybeE ( _, 16) = Nothing
maybeE (ix, iy) = Just $ mat ! (fromIntegral ix, fromIntegral iy)
-- from KL paper, page 214, U3 is sufficient despite 8 neighbors
-- because 8 (mod 8 = 0) is 0, which still leads to a False
-- (i.e. starve) as opposed to over populuation. Would be cleaner to
-- use U4, but that's another (wasted) wire for each of the 8x16
-- cells.
type NCountT = U3 -- has to be 0..8, but 8 has the same effect as 0, see above
cell :: CellT -> Signal CLK Bool -> Matrix X8 (Maybe (Signal CLK CellT)) -> Signal CLK CellT
cell init ena ns = res
where
n :: Signal CLK NCountT
n = foldr (\ a b ->
case a of
Just (v :: Signal CLK Bool) -> unsigned v + b
Nothing -> b)
0
$ M.toList ns
res :: Signal CLK CellT
res = register init $ mux ena (res, funMap life (pack (n, res)))
life :: (NCountT, CellT) -> Maybe CellT
life (2, True) = return True -- survive
life (3, True) = return True -- survive
life (3, False) = return True -- birth
life _ = return False -- starve
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment