# Conway's Game of Life with Repa

Sep. 24, 2011
1 of 12

### Conway's Game of Life with Repa

• 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>
• 3. Repa refresher -- RepaGOL.hs {-# LANGUAGE TypeOperators #-} import Data.Array.Repa (Z(..), (:.)(..)) import qualified Data.Array.Repa as R -- a 2D array (the "Toad" pattern) toad :: R.Array R.DIM2 Int toad = R.fromList (Z :. 6 :. 6) [ 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 1, 1, 1, 0 , 0, 1, 1, 1, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 ] 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>
• 8. Visualization [ 0, 0, 0, 0, 0, 0 [ 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 1, 2, 3, 2, 0 , 0, 0, 1, 1, 1, 0 , 0, 3, 4, 4, 2, 0 , 0, 1, 1, 1, 0, 0 , 0, 2, 4, 4, 3, 0 , 0, 0, 0, 0, 0, 0 , 0, 2, 3, 2, 1, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 ] ] mapStencil2 (BoundConst 0) sten 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>
• 10. We’re almost done Original Neighbors Original New state! [ 0, 0, 0, 0, 0, 0 [ 0, 0, 0, 0, 0, 0 [ 0, 0, 0, 0, 0, 0 [ 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 1, 2, 3, 2, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 1, 0, 0 , 0, 0, 1, 1, 1, 0 , 0, 3, 4, 4, 2, 0 , 0, 0, 1, 1, 1, 0 , 0, 1, 0, 0, 1, 0 , 0, 1, 1, 1, 0, 0 , 0, 2, 4, 4, 3, 0 , 0, 1, 1, 1, 0, 0 , 0, 1, 0, 0, 1, 0 , 0, 2, 3, 2, 1, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 1, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 ] ] ] ] zipWith mapStencil2 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>