Reputation: 236
I am new to Elm and have been looking at the following example (note this is under the newer 0.17 architecture, where Action is now Command): http://elm-lang.org/examples/random
There is a follow up challenge to add a second die to the example, so that a single click of the button rolls a new value for each die. My idea is to change the model to hold two separate values, one for each die, ala
type alias Model =
{ dieFace1 : Int
, dieFace2 : Int
}
This works fine until I get to the update block. I am not sure how to update the Random number generator to create two values. The function is a bit confusing to me.
type Msg
= Roll
| NewFace Int Int
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Roll ->
**(model, Random.generate NewFace (Random.int 1 6))** <-- not sure what to do here
NewFace newFace1 newFace2 ->
(Model newFace1 newFace2, Cmd.none)
The documentation for the Random.generate function is a bit light -
generate : (a -> msg) -> Generator a -> Cmd msg
Create a command that will generate random values.
Is this even the correct approach to handle two dice, or is there a better way? I am an elm noob, please be nice :)
Upvotes: 17
Views: 986
Reputation: 9879
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)
Upvotes: 0
Reputation: 15226
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
Upvotes: 1
Reputation: 36375
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.
Upvotes: 17