LoginSignup
8
2

More than 5 years have passed since last update.

Elmでじゃんけん

Last updated at Posted at 2019-06-08

追記: コメントでelmらしく書こうというアドバイスを頂いたので記事をかなり書き換えました
もしも書き換え前の記事を参考にした方がいたらごめんなさい

はじめに

Elm歴はElm Guideや「基礎からわかるElm」を一通り読んだ程度
HTML, CSS JavaScirptは基本的な構文すら勉強してない

そんな奴が書いた記事読みたくないよ~って人はブラウザバック推奨ということで・・・

ひな形を書く

module Main exposing (..)

import Browser
import Html exposing (..)

--MAIN--
main : Program () Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view
        }

--MODEL--
type alias Model =
    ()

init : () -> ( Model, Cmd Msg )
init _ =
    ( (), Cmd.none )

--UPDATE--
type alias Msg =
    Never

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    ( model, Cmd.none )

--SUBSCRIPTIONS--
subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none

--VIEW--
view : Model -> Html Msg
view model =
    div [] []

elm reactorで見てみると真っ白な画面が表示される
ひな型に追加していく形で進めていく

viewを書く

--VIEW--
view : Model -> Html Msg
view model =
    div []
        [ h1 [] [ text "Rock-paper-scissors" ]
        , h2 [] [ text "Choice your hand" ]
        , button [] [ text "Rock" ]
        , button [] [ text "Paper" ]
        , button [] [ text "Scissors" ]
        , h2 [] [ text "Result: " ]
        ]

画像のように表示される
キャプチャ.PNG

Hand型を作る

type Hand
    = Rock
    | Paper
    | Scissors

モデルを書く

先ほど作ったHand型で相手の手と自分の手を定義する

--MODEL--
type alias Model =
    { opponentHand : Hand
    , myHand : Hand
    }

init : () -> ( Model, Cmd Msg )
init _ =
    ( Model Rock Rock
    , Cmd.none
    )

RandomとHtml.Eventsのインポート

import Html.Events exposing (..)
import Random

Randomはelm install elm/randomでインストール

1~3のランダムな手を生成するgenHandを作る

--UPDATE--
genHand : Cmd Msg
genHand =
    Random.generate NewHand (Random.uniform Rock [Paper, Scissors])

updateを書く

--UPDATE--
type Msg
    = ChoiceRock
    | ChoicePaper
    | ChoiceScissors
    | NewNumber Hand

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        ChoiceRock ->
            ( { model | myHand = Rock }
            , genHand
            )

        ChoicePaper ->
            ( { model | myHand = Paper }
            , genHand
            )

        ChoiceScissors ->
            ( { model | myHand = Scissors }
            , genHand
            )

        NewHand newHand ->
            ( { model | opponentHand = newHand }
            , Cmd.none
            )

ボタンをクリックするとメッセージが送られるようにする

--VIEW--
//... 
        , button [ onClick ChoiceRock ] [ text "Rock" ]
        , button [ onClick ChoicePaper ] [ text "Paper" ]
        , button [ onClick ChoiceScissors ] [ text "Scissors" ]
//... 

勝敗結果を表示する

createResult : Model -> String
createResult model =
    case (model.myHand, model.opponentHand) of
        (Rock, Rock) ->
            "Draw"

        (Rock, Paper) ->
            "Lose"

        (Rock, Scissors) ->
            "Win"

        (Paper, Rock) ->
            "Win"

        (Paper, Paper) ->
            "Draw"

        (Paper, Scissors) ->
            "Lose"

        (Scissors, Rock) ->
            "Lose"

        (Scissors, Paper) ->
            "Win"

        (Scissors, Scissors) ->
            "Draw"

またVIEWを以下のように書き換える

--VIEW--
//... 
h2 [] [ text "Result: " ]

h2 [] [ text ("Result: " ++ (createResult model)) ]
//... 略

完成したコード

rock-paper-scissors.elm
module Main exposing (..)

import Browser
import Html exposing (..)
import Html.Events exposing (..)
import Random


--MAIN--

main : Program () Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view
        }


--MODEL--

type Hand
    = Rock
    | Paper
    | Scissors

type alias Model =
    { opponentHand : Hand
    , myHand : Hand
    }


init : () -> ( Model, Cmd Msg )
init _ =
    ( Model Rock Rock
    , Cmd.none
    )


--UPDATE--

genHand : Cmd Msg
genHand =
    Random.generate NewHand (Random.uniform Rock [Paper, Scissors])

type Msg
    = ChoiceRock
    | ChoicePaper
    | ChoiceScissors
    | NewHand Hand

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ChoiceRock ->
            ( { model | myHand = Rock }
            , genHand
            )

        ChoicePaper ->
            ( { model | myHand = Paper }
            , genHand
            )

        ChoiceScissors ->
            ( { model | myHand = Scissors }
            , genHand
            )

        NewHand newHand ->
            ( { model | opponentHand = newHand }
            , Cmd.none
            )


--subscriptions--

subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none


--VIEW--

view : Model -> Html Msg
view model =
    div []
        [ h1 [] [ text "Rock-paper-scissors" ]
        , h2 [] [ text "Choice Hand" ]
        , button [ onClick ChoiceRock ] [ text "Rock" ]
        , button [ onClick ChoicePaper ] [ text "Paper" ]
        , button [ onClick ChoiceScissors ] [ text "Scissors" ]
        , h2 [] [ text ("Result: " ++ (createResult model)) ]
        ]

createResult : Model -> String
createResult model =
    case (model.myHand, model.opponentHand) of
        (Rock, Rock) ->
            "Draw"

        (Rock, Paper) ->
            "Lose"

        (Rock, Scissors) ->
            "Win"

        (Paper, Rock) ->
            "Win"

        (Paper, Paper) ->
            "Draw"

        (Paper, Scissors) ->
            "Lose"

        (Scissors, Rock) ->
            "Lose"

        (Scissors, Paper) ->
            "Win"

        (Scissors, Scissors) ->
            "Draw"

動作確認

elm make src/rock-paper-scissors.elm --debugでindex.htmlが出力される
index.htmlを開いて右下にあるExplore Historyを開く
するとmodelの中身が表示されるのでボタンをクリックし中身が変化することを確認する

まとめ

勝敗判定の関数はもっといいアイデアがあるはずなので考えてみたい(丸々書き直しになりそうだが)
初めて記事を書いたので構成がめちゃめちゃな気がするので直したい

マサカリ大歓迎なのでよろしくお願いします

8
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2