2017-09-18 13 views
1

最近、関数型プログラミングをもっと詳しく見てみることにしたので、私はElmから始めることにしました。反復配列中のエルムデクリメントカウンタ

私は実際にこのコンセプトと言語と戦っているように感じています。私の思考プロセスはすべて間違っているので、誰かが私の簡単なエクササイズで私を助けてくれることを望んでいました。

私はMinesweeperゲームを作成しようとしています。まず、私は鉱山でグリッドを作成しようとしていました。

ここに私のコードは、これまでもちろん

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)) 

だ、このすべてが行いますが、鉱山としてすべてのセルをマークしているので、どのようにカウンターに私は私のような細胞をマークするたびにデクリメントしますか? これは些細なものでなければならないので、なぜ私はさまざまなプログラミングパラダイムに苦しんでいると思いますか?

ご協力いただきありがとうございます。 乾杯!

答えて

5

より機能的なアプローチでは、可能な限り状態を使用しないようにします。それは、一連のセルを横断してステートフルなフィールドを減らして、どれくらいの鉱山がまだ配置されていないのかを考えるのではなく、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(エルムアーキテクチャは、乱数を生成できるようになる、そこから戻ったときに使用して、この発電機を使用することができますupdate関数内)、または既知のシード値を渡してstepを実行することができます。