一个Haskell编写的生命游戏在启动时崩溃了。

12

我目前正在尝试使用Haskell开发小型的康威生命游戏。我编写了一个名为lifegame的库,可以管理单元格网格并计算它的演化(请参阅github.com/qleguennec/lifegame.git)。演化是一个无限列表。到目前为止,该库运行良好,但缺乏文档。由于这是一个小型库,应该不难理解。

现在,我的计划是将lifegamehelm相结合,将演化结果显示在屏幕上。以下是我的代码:

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

(来自:github.com/qleguennec/bats.git)

计算的重活儿在animate running status的第20行。我不太理解animate的第二个参数是什么。此外,我不确定提供一个无限的Frames列表是否合法。

当我运行代码时,游戏会冻结并在5分钟后停止。似乎消耗了所有内存并崩溃了。现在,我明白这一切都缺乏文档。我正在努力改进。但是,作为一个新手 Haskeller 和 FRP/SDL 开发人员,我需要知道我是否做错了(我可能确实做错了)。 欢迎并推荐任何意见。谢谢。

1个回答

1
我不知道我能否帮助您了解FRP - 有很多库,我自己也没有太多实践经验 - 但是就价值而言(因为您说您对Haskell相当新),Conway的生命游戏可以轻松地在没有使用FRP的情况下编写,并且使用SDL进行渲染也很简单。
我发现将游戏表示为一组坐标对比数组更好 - 这样,您就不必担心边界条件或环绕世界的问题。(您可以从hashmap和unordered-containers包中获取高效的严格或惰性集合。
CA逻辑看起来像这样:
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

主程序循环如下所示:

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

要查看完整的实现,包括大多数FRP所带来的功能(通过鼠标编辑网格)等等,请查看此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接