1. Conway’s Game of Life with Repa
worked example using “Stencil Convolution”
from Illustrated Haskell <http://illustratedhaskell.org>
2. Preliminaries
Short tutorial from HaskellWiki
http://www.haskell.org/haskellwiki/Numeric_Haskell:_A_Repa_Tutorial
What is this Game of Life?
http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
This example demonstrates how to use Repa’s
“Stencil Convolution” to solve a simple problem.
You should be totally familiar with Repa and Game
of Life, otherwise what follows will not make any
sense!
Illustrated Haskell <http://illustratedhaskell.org>
4. “Stencil Convolution”
This is one of those things better explained by
example than in words, and is way simpler than it
sounds.
Here is how a stencil looks like in Repa
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
sten :: Stencil DIM2 Int
sten = [stencil2| 1 1 1
1 0 1
1 1 1 |]
This is a 3x3 stencil
Illustrated Haskell <http://illustratedhaskell.org>
5. So what is “Stencil Convolution”?
Applying a stencil to an “image” means
1. Put the stencil kernel on every pixel
2. Grab all neighbors and multiply with the
corresponding stencil value
3. Add them all and it becomes the new value of the
pixel
Doesn’t that sound like how you would implement
GoL using imperative loops?
Illustrated Haskell <http://illustratedhaskell.org>
6. Stencil Convolution example
sten :: Stencil DIM2 Int Since the image is the
sten = [stencil2| 1 1 1
1 0 1 same size of the stencil
1 1 1 |] kernel, it can only be
applied on the central
x1 :: R.Array DIM2 Int pixel.
x1 = R.formList (Z :. 3 :. 3)
[ 1, 2, 3 1 + 2 + 3 + 4 + 5 = 15 is the
, 4, 9, 5 new value of the central
, 0, 0, 0 ] pixel
conv1 = mapStencil2 (BoundConst The 9 is not included
0) sten x1 because the center
-- Result: [ 0, 0, 0
-- , 0, 15, 0
pixel of the kernel is 0
-- , 0, 0, 0 ]
Illustrated Haskell <http://illustratedhaskell.org>
7. How to use stencil convolution in Game of
Life
It should now become pretty obvious
If we represent live cells as 1, dead cells as 0
The stencil we just defined be used to count the
number of neighbors for each cell!
Illustrated Haskell <http://illustratedhaskell.org>
9. And what does the rule say?
-- A literal translation of the rules
-- from Wikipedia
transit 1 2 = 1
transit 1 3 = 1
transit 1 _ = 0
transit 0 3 = 1
transit 0 _ = 0
Illustrated Haskell <http://illustratedhaskell.org>
11. How about codifying it?
tick world = R.force $ R.zipWith transit world neighbors
where neighbors = mapStencil 2 (BoundConst 0) sten world
Illustrated Haskell <http://illustratedhaskell.org>
12. And putting it in a program…
gameOfLife world = do
show2D 6 world
input <- getLine
case input of
"q" -> return ()
_ -> program $ tick world
main = program toad
That’s it! Hopefully you are now as fluent with Repa
as with lists!
Illustrated Haskell <http://illustratedhaskell.org>