迭代数组时 Elm 递减计数器

Elm decrement counter while iterating array

我最近决定更深入地研究函数式编程,并决定从 Elm 入手。

我对此非常缺乏经验,所以我觉得我实际上在与概念和语言作斗争,我的思维过程完全错误,所以我希望有人能帮助我进行简单的练习。

我正在尝试创建一个扫雷游戏,对于初学者来说,我只是想用地雷填充一个网格。

到目前为止,这是我的代码

import Array exposing (Array)


type State = Hidden | Tagged | Revealed
type alias Cell = {isMine: Bool, nearbyMines: Int, state: State}
type alias Board = Array (Array Cell)

mines : Int
mines = 100

initCell : Cell
initCell = 
  {isMine = False, nearbyMines = 0, state = Hidden}

generate : Int -> Int -> Board
generate lines cols =
  Array.initialize lines (\y -> 
    Array.initialize cols (\x -> initCell))


markAsMine : Int -> Int -> Cell -> Cell
markAsMine x y cell =         
    if mines > 0
    then {cell | isMine = True}
    else cell

fillMines : Int -> Board -> Board
fillMines amount board =
  board
    |> Array.indexedMap (\y row -> row |> Array.indexedMap (\x cell-> markAsMine x y cell))

当然,所有这一切都是将每个单元格标记为我的,那么每次我将一个单元格标记为我的时如何减少计数器? 这应该是微不足道的事情,因此我认为我正在为不同的编程范式而苦苦挣扎!

在此先感谢您的帮助, 干杯!

一种更实用的方法是尽可能避免使用状态。与其考虑遍历一组单元格并递减一个有状态的字段来告诉你有多少地雷尚未放置,传递一个 Set(x, y) 值会更惯用已被确定为地雷。

import Set exposing (Set)

fillMines : Int -> Set ( Int, Int ) -> Board -> Board
fillMines amount mines board =
    board
        |> Array.indexedMap
            (\y row ->
                row |> Array.indexedMap (\x cell -> { cell | isMine = Set.member ( x, y ) mines })
            )

然后您将确定哪些 (x, y) 单元格是地雷的责任转移到应用程序的其他地方,并且由于扫雷是一款随机游戏,您可能希望创建一组随机单元格作为地雷.类型签名可能如下所示:

import Random

minefieldGenerator : Int -> Int -> Int -> Random.Generator (Set (Int, Int))
minefieldGenerator lines cols numMines = ...

minefieldGenerator 的实现超出了这个问题的范围,但是您可以使用 Random.generate (which will let the Elm Architecture generate a random number when returned from inside an update function), or you can pass in a known seed value to execute step.

来使用这个生成器