在Haskell中的Minesweeper克隆中管理状态

时间:2014-06-29 10:09:31

标签: haskell

作为学习Haskell的一种方法,我决定制作扫雷克隆。我已经写了一些代码,程序的主要结构已经准备就绪。它基于:

  • Board,其中包含amount个地雷,fields以及地图的widthheight列表。
  • A Field,包含相邻地雷的数量或表示该地块本身就是地雷的值。 Field还包含FieldStateMarkedHiddenShown)。

游戏循环如下所示:

play board = do
    -- Clear the screen
    putStrLn $ replicate 40 '\n'

    -- Show the board
    print board

    -- Get and process user input
    putStr "Command: "
    -- We are generating a new board to reflect the changes!
    newBoard <- parseInput board <$> getLine

    -- If the game is not ended, go to next step
    if gameEnded newBoard
    then return $ result newBoard
    else play newBoard

现在效果非常好,但我不喜欢这样一个事实,即每次转弯后我都必须生成一个新的Board。从像C ++这样的命令式语言来看,它看起来效率低下,你只需要改变现有的电路板。

重点:

  • 这是正确的方法吗?
  • 是否会被编译器优化?

1 个答案:

答案 0 :(得分:4)

你当然是对的,完全更换电路板不是最佳的,但它并不一定像你想象的那么糟糕。如果Board使用[[FieldState]] - 2D网格,那么更新单个单元实际上会重新使用大部分行(这可以不用考虑而且完全安全,因为 Haskell纯粹是功能性的:对于 n × n 网格,复杂性是 O n ),只有一个常量比起查找任何给定字段所需的因素更糟糕。对于像扫雷这样的游戏来说,绝对不会有任何问题。

对于性能更关键的内容,有专门的数组类型可以同时查找和更新 O 中的单个字段(IOST monad) (1)。对于类似于你的应用程序,Data.Array.MArray可能是最合适的(尽管社区中存在某种趋势,而是在较低级别,更优化的vector类型周围编写您的抽象。)< / p>