2016-05-14 8 views
13

Sono nuovo di Elm e sono stati a guardare l'esempio seguente (notare che questo è sotto il 0,17 architettura più recente, in cui l'azione è ora Comando): http://elm-lang.org/examples/randomCome aggiungere un secondo dado a questo esempio di effetti elm?

C'è un follow-up sfida per aggiungere un secondo dado per l'esempio, in modo che un singolo clic del pulsante tiri un nuovo valore per ogni dado. La mia idea è quella di cambiare il modello di tenere due valori separati, uno per ogni dado, ala

type alias Model = 
     { dieFace1 : Int 
     , dieFace2 : Int 
     } 

Questo funziona bene fino a ottenere al blocco di aggiornamento. Non sono sicuro di come aggiornare il generatore di numeri casuali per creare due valori. La funzione è un po 'confusa per 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) 

La documentazione per la funzione Random.generate è un po 'di luce -

generano: (a -> msg) -> Generatore a -> Cmd msg

creare un comando che genererà valori casuali.

È questo anche l'approccio corretto per gestire due dadi, o c'è un modo migliore? Sono un olmo noob, per favore sii gentile :)

risposta

13

Random.int è un generatore primitivo che ti dà un singolo int casuale. Hai bisogno di un generatore che ti dà esattamente due numeri interi casuali.

Generatori di numeri casuali possono essere creati da generatori più primitivi per creare generatori più complessi. Fortunatamente, Elm ha proprio questa funzione, Random.pair, che ti permette di specificare quali due generatori vuoi per ogni parte della tupla.

Diamo tirare il generatore di morire nella propria funzione per evitare di ripetere a noi stessi:

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

Ora siamo in grado di costruire un altro generatore che ci dà il valore casuale di un paio di stampo:

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

Poiché abbiamo a che fare con una tupla di interi, aggiorniamo la tua definizione Msg di NewFace Int Int a NewFaces (Int, Int). Che permettono al gestore Roll ad essere bello e pulito:

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

Se si vuole provare a spostare al di là di questo, pensare a quello che ci vorrebbe per consentire qualsiasi numero di dado per essere arrotolato. Prendi quest'idea di costruire generatori complessi da generatori più primitivi e usa la documentazione per il modulo Random come guida.

+0

impressionante, grazie per i puntatori alla parte corretta della documentazione, anche. Sembra che fare n numero di tiri di dado possa comportare la parametrizzazione di un Random.list di Random.ints per contenere il numero di dadi desiderati, penso. Grazie per la risposta e i nuovi compiti. – TonyM

+1

Grazie a Chad per aver spiegato nei dettagli. Ha funzionato come un fascino. Ho creato un sommario per i pigri: https://gist.github.com/dotcs/3b3626cfbe5b0744134f7af8edcb32c5 – dotcs

+1

Come appare la soluzione se non ci aspettiamo una tupla di parametri 'Int', ma _two_' Int'? Cioè se 'Msg' è definito come' NewFaces Int Int 'come intuito dall'OP? –

1

Un approccio è utilizzare batch come qui https://gist.github.com/davidchase/40c27042bccfb00d786af0360b5bc3ea.

Un altro è quello di utilizzare Random.pair o Random.list se avete bisogno di più di 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" ] 
    ] 

e un altro https://github.com/jcollard/random-examples/blob/master/src/Dice.elm