tia*_*ive 1 functional-programming elm
我最近决定更深入地研究函数式编程,我决定从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))
Run Code Online (Sandbox Code Playgroud)
当然,所有这一切都将每个单元标记为一个地雷,那么每当我将单元标记为我的时,如何减少计数器?这应该是微不足道的,因此我认为我正在努力应对不同的编程范式!
在此先感谢您的帮助,干杯!
更有效的方法是尽可能避免使用状态.不是在遍历一组单元格和减少有状态字段来考虑它尚未放置多少地雷方面而是考虑它,而是传递已经确定为地雷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 })
)
Run Code Online (Sandbox Code Playgroud)
然后,您将确定哪些(x, y)单元格是地雷的责任转移到应用程序的其他位置,并且由于Minesweeper是一个随机游戏,您可能希望创建一个随机的单元格集合作为地雷.类型签名可能如下所示:
import Random
minefieldGenerator : Int -> Int -> Int -> Random.Generator (Set (Int, Int))
minefieldGenerator lines cols numMines = ...
Run Code Online (Sandbox Code Playgroud)
实现minefieldGenerator超出了本问题的范围,但您可以使用此生成器Random.generate(这将使Elm Architecture从update函数内部返回时生成随机数),或者您可以传入已知的种子值来执行step.