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 1NewFace 4などのメッセージに変換されます。ランダムなサイコロの目を得るために必要なのはこれで全てですが、乱数生成器にはもっと様々な使い方があります!

乱数生成器の結合

probabilityusuallyTrueといったシンプルな乱数生成器を一度用意すれば、それらを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つを同時に振ってみましょう。
  • サイコロの目が決まる前に、ランダムにサイコロの目が切り替わるようにしてみましょう。

results matching ""

    No results matching ""