How do I add a second die to this elm effects example?

丶灬走出姿态 提交于 2019-12-03 22:51:55

Random.int is a primitive generator that gives you a single random int. You need a generator that gives you exactly two random integers.

Random number generators can be built up from more primitive generators to create more complex generators. Fortunately, Elm has just such a function, Random.pair which lets you specify which two generators you want for each part of the tuple.

Let's pull the die generator into its own function to avoid repeating ourselves:

dieGenerator : Random.Generator Int
dieGenerator =
  Random.int 1 6

Now we can build another generator that gives us the random value of a pair of die:

diePairGenerator : Random.Generator (Int, Int)
diePairGenerator =
  Random.pair dieGenerator dieGenerator

Since we're dealing with a tuple of ints, let's update your Msg definition of NewFace Int Int to NewFaces (Int, Int). That will allow your Roll handler to be nice and clean:

Roll ->
  (model, Random.generate NewFaces diePairGenerator)

If you want to try moving beyond this, think about what it would take to allow for any number of die to be rolled. Take this idea of building complex generators from more primitive generators and use the documentation for the Random module us a guide.

One approach is to use batch like here https://gist.github.com/davidchase/40c27042bccfb00d786af0360b5bc3ea.

Another is to use Random.pair or Random.list if you need more than 2:

import Html exposing (..)
import Html.App as Html
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import Random


main : Program Never
main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

-- MODEL

type alias Model =
  { dieFaces : (List Int)
  }

-- http://stackoverflow.com/questions/23199398/how-do-i-get-a-list-item-by-index-in-elm#comment56252508_23201661
get : Int -> List a -> Maybe a
get n xs = List.head (List.drop n xs)

-- http://rundis.github.io/blog/2016/elm_maybe.html
getOrOne : Int -> List Int -> Int
getOrOne n xs = Maybe.withDefault 1 (get n xs)

init : (Model, Cmd Msg)
init =
  (Model [1, 1], Cmd.none)

-- UPDATE

type Msg
  = Roll
  | NewFace (List Int)

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Roll ->
      (model, Random.generate NewFace (Random.list 2 (Random.int 1 6)))

    NewFace newFace ->
      (Model newFace, Cmd.none)

-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.none

-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ img [ src ("/img/Alea_" ++ toString (getOrOne 0 model.dieFaces) ++ ".png")] []
    , img [ src ("/img/Alea_" ++ toString (getOrOne 1 model.dieFaces) ++ ".png")] []
    , button [ onClick Roll ] [ text "Roll" ]
    ]

and another https://github.com/jcollard/random-examples/blob/master/src/Dice.elm

Apart from changes described in the accepted answer by @ChadGilbert, I had to change NewFaces update case too (using elm 0.18.0).

NewFaces newFaces ->
  let
    (newFace1, newFace2) = newFaces
  in
    (Model newFace1 newFace2, Cmd.none)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!