我最近决定更深入地研究函数式编程,我决定从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))
当然,所有这一切都将每个单元标记为一个地雷,那么每当我将单元标记为我的时,如何减少计数器? 这应该是微不足道的,因此我认为我为什么要在不同的编程范式中挣扎!
提前感谢您的帮助, 干杯!
答案 0 :(得分:5)
更有效的方法是尽可能避免使用状态。不是通过遍历一组单元格并递减有状态字段来告诉您尚未放置多少个地雷,而是通过传递Set
List<T>
个值来更加惯用已经被确定为地雷。
(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 })
)
单元格是地雷的责任转移到应用程序的其他位置,并且由于Minesweeper是一个随机游戏,您可能希望创建一个随机的单元格集合作为地雷。类型签名可能如下所示:
(x, y)
import Random
minefieldGenerator : Int -> Int -> Int -> Random.Generator (Set (Int, Int))
minefieldGenerator lines cols numMines = ...
的实现超出了本问题的范围,但您可以使用Random.generate
使用此生成器(这将使Elm Architecture从{{1}内部返回时生成随机数您可以传入已知的种子值来执行step
。