Valores aleatorios

Hasta ahora sólo hemos visto comandos que realizan solicitudes HTTP, pero también existen otros comandos, como aquellos que general valores aleatorios. Vamos a crear una aplicación que tira un dado y produce un valor entre 1 y 6.

Apreta el botón azul “Editar” para ver este ejemplo en acción. Genera algunos números aleatorios y revisa el código para tratar de interpretar cómo funciona. Apreta el botón azul.

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" ]
        ]

Lo nuevo aquí es el comando generado en la función update:

Random.generate NewFace (Random.int 1 6)

Generar valores aleatorios funciona un poco distinto en comparación con otros lenguajes como JavaScript, Python, Java, etc. Veamos cómo funciona en Elm.

Generadores de valores aleatorios

Usamos el paquete elm/random para esto. En particular, el módulo Random.

La idea fundametal es que tenemos un generador Generator que describe cómo vamos a generar el valor aleatorio. Por ejemplo:

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 ) ]

Aquí tenemos tres generadores de valores aleatorios. El generador roll dice que producirá un Int, y más específicamente, uno entre 1 y 6, inclusivos. Similarmente, el generador usuallyTrue dice que producirá un Bool, y más específicamente, que éste será True el 80% de las veces.

El punto es que no estamos aún generando los valores. Estamos sólo describiendo cómo generarlos. Después podemos usar Random.generate para convertirlo en un comando:

generate : (a -> msg) -> Generator a -> Cmd msg

Cuando el comando se ejecuta, el Generator produce un valor, y éste se convierte en un mensaje para la función update. En nuestro ejemplo, el Generator produce un valor entre 1 y 6, y después se convierte en un mensaje como NewFace 1 o NewFace 4. Eso es todo lo que necesitamos para poder lanzar el dado, pero los generadores pueden hacer mucho más.

Combinando generadores

Teniendo generadores simples como probability o usuallyTrue, podemos empezar a conjugarlos usando funciones como map3. Imagina que quisiéramos hacer una máquina tragamonedas. Podríamos tener un generador como este:

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

Primero creamos Symbol para describir los símbolos que aparecen en la máquina tragamonedas. Después creamos un generador que otorga la misma probabilidad a cada símbolo.

Después usamos map3 para combinarlos en un nuevo generador spin. Lo que hace es generar tres símbolos y después unirlos en un valor Spin.

El punto es que a partir de estas piezas básicas podemos crear un Generator que describe comportamientos bastante complejos. Y desde nuestra aplicación, sólo necesitamos decir algo como Random.generate NewSpin spin para obtener el siguiente valor aleatorio.

Ejercicios: Estas son algunas ideas para hacer más interesante el código que vimos en esta página.

  • En vez de mostrar un número, muestra la cara del dado como imagen.
  • En vez de mostrar una imagen de un dado, usa elm/svg para dibujarla por tu cuenta.
  • Crea un dado “tramposo” usando Random.weighted.
  • Añade un segundo dado y haz que se tiren ambos al mismo tiempo.
  • Haz que el dado gire aleatoriamente antes de caer sobre su valor final.

results matching ""

    No results matching ""