Main.elm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. module Cellular exposing (..)
  2. import Html exposing (..)
  3. import Html.Events exposing (..)
  4. import Html.Attributes exposing (id, class, classList, style)
  5. import Array
  6. import Random
  7. import Time exposing (Time, second)
  8. type Cell
  9. = Alive
  10. | Dead
  11. type alias Board = Array.Array (Array.Array Cell)
  12. type alias Rule = Int -> Cell -> Cell
  13. type alias Model =
  14. { board : Board
  15. , rule : Rule
  16. }
  17. initModel : Model
  18. initModel =
  19. { board = Array.empty
  20. --, board = modify 4 4 Alive <| modify 5 5 Alive <| modify 6 5 Alive <| modify 6 4 Alive <| modify 6 3 Alive <| Array.repeat h <| Array.repeat w Dead
  21. , rule = (\livingNeighbours cell ->
  22. case cell of
  23. Alive ->
  24. if livingNeighbours < 2 || livingNeighbours > 3 then
  25. Dead
  26. else
  27. Alive
  28. _ ->
  29. if livingNeighbours == 3 then
  30. Alive
  31. else
  32. Dead)
  33. }
  34. type Msg
  35. = NoOp
  36. | Step
  37. | SetBoard Board
  38. viewRow row =
  39. tr
  40. []
  41. <|
  42. Array.toList
  43. <|
  44. Array.map (\c ->
  45. let
  46. cellClass =
  47. case c of
  48. Alive -> "alive"
  49. Dead -> "dead"
  50. in
  51. td
  52. [ class ("cell " ++ cellClass)
  53. ]
  54. []
  55. ) row
  56. viewBoard : Board -> Html Msg
  57. viewBoard board =
  58. table
  59. []
  60. <|
  61. Array.toList
  62. <|
  63. Array.map (\r -> viewRow r) board
  64. view : Model -> Html Msg
  65. view model =
  66. div
  67. [ onClick Step
  68. ]
  69. [ viewBoard model.board
  70. ]
  71. modify : Int -> Int -> Cell -> Board -> Board
  72. modify x y newState board =
  73. case Array.get y board of
  74. Just oldRow ->
  75. let
  76. newRow = Array.set x newState oldRow
  77. newBoard = Array.set y newRow board
  78. in
  79. newBoard
  80. Nothing ->
  81. board
  82. valueAt : Int -> Int -> Board -> Cell
  83. valueAt r c board =
  84. Maybe.withDefault Dead <| Array.get c <| Maybe.withDefault Array.empty (Array.get r board)
  85. surroundings : Int -> Int -> Board -> Int
  86. surroundings r c board =
  87. let
  88. living cell =
  89. case cell of
  90. Alive -> 1
  91. _ -> 0
  92. ul = living <| valueAt (r - 1) (c - 1) board
  93. uc = living <| valueAt (r - 1) c board
  94. ur = living <| valueAt (r - 1) (c + 1) board
  95. ml = living <| valueAt r (c - 1) board
  96. mr = living <| valueAt r (c + 1) board
  97. ll = living <| valueAt (r + 1) (c - 1) board
  98. lc = living <| valueAt (r + 1) c board
  99. lr = living <| valueAt (r + 1) (c + 1) board
  100. in
  101. ul + uc + ur + ml + mr + ll + lc + lr
  102. replaceRow : Rule -> Board -> Int -> Array.Array Cell -> Array.Array Cell
  103. replaceRow rule board rn row =
  104. let
  105. prevRow =
  106. Maybe.withDefault Array.empty <| Array.get (rn - 1) board
  107. nextRow =
  108. Maybe.withDefault Array.empty <| Array.get (rn + 1) board
  109. in
  110. Array.indexedMap
  111. (\cn cell ->
  112. rule (surroundings rn cn board) cell
  113. ) row
  114. step : Rule -> Board -> Board
  115. step rule board =
  116. Array.indexedMap (replaceRow rule board) board
  117. update : Msg -> Model -> (Model, Cmd Msg)
  118. update msg model =
  119. case msg of
  120. Step ->
  121. ( { model | board = step model.rule model.board }, Cmd.none )
  122. SetBoard board ->
  123. ( { model | board = board }, Cmd.none )
  124. _ ->
  125. ( model, Cmd.none )
  126. generateRandom : Int -> Int -> Random.Generator Board
  127. generateRandom nr nc =
  128. Random.map Array.fromList <| Random.list nr <| Random.map Array.fromList <| Random.list nc <| Random.map (\n -> if n == 1 then Alive else Dead) (Random.int 1 4)
  129. subscriptions : Model -> Sub Msg
  130. subscriptions model =
  131. Sub.batch
  132. [ Time.every (second*3) (\_ -> Step)
  133. ]
  134. main =
  135. Html.program
  136. { init = (initModel, Random.generate SetBoard (generateRandom 50 100))
  137. , view = view
  138. , update = update
  139. , subscriptions = subscriptions
  140. }