Random (Valeurs aléatoires)
Jusqu'à présent, nous n'avons vu que des commandes pour effectuer des requêtes HTTP, mais nous pouvons commander d'autres choses, comme générer des valeurs aléatoires ! Nous allons donc créer une application qui lance des dés et produit un nombre aléatoire entre 1 et 6.
Cliquez sur le bouton bleu "Edit" pour voir cet exemple en action. Générez quelques nombres aléatoires, et regardez le code pour essayer de comprendre comment cela fonctionne. Cliquez sur le bouton bleu maintenant !
import Browser
import Html exposing (..)
import Html.Events exposing (..)
import Random
-- MAIN
main =
Browser.element
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
}
-- MODEL
type alias Model =
{ dieFace : Int
}
init : () -> (Model, Cmd Msg)
init _ =
( Model 1
, Cmd.none
)
-- UPDATE
type Msg
= Roll
| NewFace Int
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Roll ->
( model
, Random.generate NewFace (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 []
[ h1 [] [ text (String.fromInt model.dieFace) ]
, button [ onClick Roll ] [ text "Roll" ]
]
La nouveauté ici est la commande émise dans la fonction update
:
Random.generate NewFace (Random.int 1 6)
La génération de valeurs aléatoires fonctionne un peu différemment que dans des langages comme JavaScript, Python, Java, etc. Voyons donc comment cela fonctionne dans Elm !
Générateurs aléatoires
Nous utilisons le paquet elm/random
pour cela. Le module Random
en particulier.
L'idée de base est que nous avons un Generator
aléatoire qui décrit comment générer une valeur aléatoire. Par exemple :
import Random
probability : Random.Generator Float
probability =
Random.float 0 1
roll : Random.Generator Int
roll =
Random.int 1 6
usuallyTrue : Random.Generator Bool
usuallyTrue =
Random.weighted (80, True) [ (20, False) ]
Nous avons donc ici trois générateurs aléatoires. Le générateur roll
dit qu'il produira un Int
, et plus précisément, qu'il produira un entier entre 1
et 6
inclus. De même, le générateur usuallyTrue
dit qu'il produira un Bool
, et plus précisément, qu'il sera vrai 80% du temps.
En réalité, nous ne sommes pas encore en train de générer les valeurs. Nous décrivons simplement comment les générer. À partir de là, vous pouvez utiliser Random.generate
pour la transformer en commande :
generate : (a -> msg) -> Generator a -> Cmd msg
Lorsque la commande est exécutée, le Generator
produit une valeur, qui est ensuite transformée en un message pour votre fonction update
. Ainsi, dans notre exemple, le Generator
produit une valeur entre 1 et 6, et la transforme en un message comme NewFace 1
ou NewFace 4
. C'est tout ce que nous avons besoin de savoir pour obtenir nos lancers de dés aléatoires, mais les générateurs peuvent faire beaucoup plus !
Combiner des générateurs
Une fois que nous avons des générateurs simples comme probability
et usuallyTrue
, nous pouvons commencer à les assembler avec des fonctions comme map3
. Imaginons que nous voulions créer une simple machine à sous. Nous pourrions créer un générateur comme celui-ci :
import Random
type Symbol = Cherry | Seven | Bar | Grapes
symbol : Random.Generator Symbol
symbol =
Random.uniform Cherry [ Seven, Bar, Grapes ]
type alias Spin =
{ one : Symbol
, two : Symbol
, three : Symbol
}
spin : Random.Generator Spin
spin =
Random.map3 Spin symbol symbol symbol
Nous créons d'abord Symbol
pour décrire les images qui peuvent apparaître sur la machine à sous. Nous créons ensuite un générateur aléatoire qui génère chaque symbole avec une probabilité égale.
À partir de là, nous utilisons map3
pour les combiner dans un nouveau générateur spin
. Il dit de générer trois symboles et de les combiner en un Spin
.
Ce qui est important ici est qu'à partir de petits blocs de construction, nous pouvons créer un Generator
qui décrit un comportement assez complexe. Ensuite, dans notre application, il suffit de dire quelque chose comme Random.generate NewSpin spin
pour obtenir la prochaine valeur aléatoire.
Exercices: Voici quelques idées pour rendre le code d'exemple de cette page un peu plus intéressant !
- Au lieu de montrer un nombre, montrez la face du dé sous forme d'image.
- Au lieu d'afficher une image de la face d'un dé, utilisez
elm/svg
pour la dessiner vous-même.- Créez un dé pondéré avec
Random.weighted
.- Ajoutez un deuxième dé et faites-les lancer en même temps.
- Faites en sorte que les dés se retournent de manière aléatoire avant de choisir une valeur finale.