Random
これまで見てきたコマンドはHTTPリクエストを送るためのコマンドだけでしたが、ランダムな値を生成するというような他のコマンドを発行することもできます。この節ではサイコロを振って1から6のランダムな数字を生成するアプリケーションを作っていきましょう。
青い "Edit" ボタンをクリックしてこの節の例が動いている様子を見てみましょう。実際にいくつかランダムな値を生成してみてください。それからコードに目を通してどんな仕組みになっているのか調べてみましょう。今すぐ青いボタンをクリック!
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" ]
]
ここでの新しい部分はupdate
関数の中で発行されるコマンドです:
Random.generate NewFace (Random.int 1 6)
乱数生成の方法はJavaScript、Python、Javaやその他の言語とはやや異なります。Elmの場合にどのようになるか見ていきましょう!
乱数生成器
乱数を生成するには elm/random
パッケージにある Random
モジュールを使います。
ここで中心となる概念は、乱数生成の方法が記述された乱数生成器Generator
を使うということです。例えば:
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) ]
ここでは3つの乱数生成器が定義されています。乱数生成器roll
関数はInt
型の値を生成すると定義されており、実装としては1
から6
までの整数の値を生成します。同様に、乱数生成器usuallyTrue
関数はBool
型の値を生成すると定義されており、実装としては80%の確率で真となります。
大事な点はこの段階では値の生成は実際には行われていないということです。その値を生成するための方法が記述されているだけです。そこからRandom.generate
を使ってコマンドに変換します:
generate : (a -> msg) -> Generator a -> Cmd msg
このコマンドが実行されると、Generator
は何らかの値を生成し、あなたのコードのupdate
関数で処理されるメッセージに変換されます。我々の例ではGenerator
は1から6の間の値を生成し、NewFace 1
やNewFace 4
などのメッセージに変換されます。ランダムなサイコロの目を得るために必要なのはこれで全てですが、乱数生成器にはもっと様々な使い方があります!
乱数生成器の結合
probability
や usuallyTrue
といったシンプルな乱数生成器を一度用意すれば、それらをmap3
のような関数によって結合することができるようになってきます。シンプルなスロットマシーンを作りたくなったとしましょう。例えば次のような乱数生成器を作ることができます:
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
最初にスロットマシーンの絵柄を表すためのSymbol
型を用意します。そして同じ確率でそれぞれの絵柄を返す乱数生成器を作ります。
次にmap3
関数を使ってこの乱数生成器を結合して新たな乱数生成器spin
を作ります。3つの絵柄を生成しそれらをSpin
型の値にまとめるということを示しています。
ここで大事な点は、小さな構成要素から始めてとても複雑なふるまいをするGenerator
を生成できるということです。また、サイコロアプリケーションから分かる通り、新しい乱数値を得るためにはRandom.generate NewSpin spin
のように呼び出すだけでよいのです。
練習問題: この例のコードをもう少し楽しいものにするためにいくつかのアイデアがあります!
- 数字の代わりにサイコロの面を画像で表示してみましょう。
- サイコロの面を画像で表示する代わりに、
elm/svg
を使って実際に描いてみましょう。- 出る目の確率が偏ったサイコロを
Random.weighted
で作ってみましょう。- 2個目のサイコロを追加して、2つを同時に振ってみましょう。
- サイコロの目が決まる前に、ランダムにサイコロの目が切り替わるようにしてみましょう。