Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A Haskell Game of life crashes when launched

I'm currently trying to develop a tiny Conway's Game of Life in Haskell. I wrote a library, lifegame, that enables to manage a grid of cells and to compute its generations (see github.com/qleguennec/lifegame.git). Generations is an infinite list. So far, the library is working great, but lacks documentation. This is a small library and it shouldn't be so hard to get in it.

Now, what I'm here for is, I'm trying to use lifegame coupled with helm to actually show generations to the screen. Here's what I wrote:

import FRP.Helm
import FRP.Helm.Graphics (Element(..))
import qualified FRP.Helm.Window as Window
import FRP.Helm.Animation (Frame, AnimationStatus(..), animate, absolute)
import FRP.Helm.Time (second, running, delta)
import FRP.Elerea.Simple

import Cell.Display (allGenFrames)
import LifeGame.Data.CellGrid (CellGrid(..), randCellGrid)

render :: Form -> (Int, Int) -> Element
render form (x, y) = collage x y $ [form]

main :: IO ()
main = do
  cg <- randCellGrid 50 50
  anim <- return . absolute $ allGenFrames cg (1 * second) 10
  engine <- startup defaultConfig

  run engine $ render <~ (animate anim running status) ~~ Window.dimensions engine

  where
    config = defaultConfig { windowTitle = "bats"
                           , windowDimensions = (500, 500)}
    status = effectful $ getLine >>= \i -> return $
      case i of
        "Pause" -> Pause
        "Stop" -> Stop
        "Cycle" -> Cycle

(from: github.com/qleguennec/bats.git)

The hard work of the computation lives in animate running status", line 20. I don't really understand what the second argument of animate is. Besides, I'm not sure that feeding an infinite list of Frames is legit.

When I launch the code, the game freezes and stops 5 min afterwards. It seems to consume all memory and crash. Now, I understand that all of this lacks documentation. I'm working on it. But, being baby Haskeller, and a baby FRP/SDL developer, I need to know if I'm doing this the wrong way (and I probably do). Any comment accepted and recommended. Thanks.

like image 258
qleguennec Avatar asked Jul 05 '14 06:07

qleguennec


1 Answers

I don't know if I can help you with FRP - there are so many libraries and I haven't played with it much myself - but for what it's worth (since you say you're pretty new to Haskell), Conway's Life can be written easily without FRP, and rendering it with SDL is simple.

I find it best to represent the game as a set of coordinate pairs, rather than an array - that way, you don't have boundary conditions or world-wrapping problems. (You can get efficient strict or lazy sets from the hashmap and unordered-containers packages.

The CA logic then looks like this:

next cs = [i | (i,n) <- M.toList neighbors,
           n == 3 || (n == 2 && S.member i cs')]
 where
  cs'         = S.fromList cs
  moore (x,y) = tail $ liftM2 (,) [x, x+1, x-1] [y, y+1, y-1]
  neighbors   = M.fromListWith (+) $ map (,1) $ moore =<< cs

The main program loop looks like this:

run w cs = do
  drawCells w cs
  e <- pollEvent
  case e of
   KeyUp (Keysym SDLK_ESCAPE _ _) -> return ()
   KeyUp (Keysym SDLK_SPACE  _ _) -> pause w cs
   _                              -> run w $ next cs

drawCells w cs = do
  fillRect w (Just $ Rect 0 0 xres yres) (Pixel 0)
  c <- createRGBSurface [SWSurface] cellSz cellSz 32 0 0 0 0
  mapM_ (draw c . scale) cs
  SDL.flip w
 where
  rect (x,y) = Just $ Rect x y cellSz cellSz
  scale      = join (***) (* cellSz)
  draw c p   = do fillRect c Nothing $ Pixel 0xFFFFFF
                  blitSurface c Nothing w $ rect p

To see the full implementation, with most of what FRP would get you (editing the grid via mouse) and more, take a look at this.

like image 168
sacheie Avatar answered Oct 19 '22 00:10

sacheie