Haskell Game of Life вылетает при запуске

В настоящее время я пытаюсь разработать крошечную игру Conway of Life в Хаскелле. Я написал библиотеку, lifegame, которая позволяет управлять сеткой ячеек и вычислять ее поколения (см. github.com/qleguennec/lifegame.git). Поколения - это бесконечный список. Пока библиотека работает отлично, но не хватает документации. Это небольшая библиотека, и в нее не должно быть так сложно.

Теперь, для чего я здесь, я пытаюсь использовать lifegame в сочетании с рулем, чтобы на самом деле показать поколениям на экране. Вот что я написал:

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)

Тяжелая работа вычислений живет в строке animate running status ", строка 20. Я не совсем понимаю, что такое второй аргумент анимации. Кроме того, я не уверен, что подача бесконечного списка фреймов является законным.

Когда я запускаю код, игра замерзает и останавливается через 5 минут. Кажется, он потребляет всю память и краш. Теперь я понимаю, что все это не хватает документации. Я работаю над этим. Но, будучи ребенком Хаскеллером и разработчиком FRP/SDL для детей, мне нужно знать, буду ли я делать это неправильно (и, вероятно, я это делаю). Любые комментарии принимаются и рекомендуются. Спасибо.

Ответ 1

Я не знаю, смогу ли я помочь вам с FRP - там так много библиотек, и я не очень много играл с ним - но для чего это стоит (поскольку вы говорите, что вы довольно новичок в Haskell) Conway Life можно легко писать без 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 получит вам (редактирование сетки с помощью мыши) и т.д., взгляните на это.