LoginSignup
11
1

More than 3 years have passed since last update.

判断が遅いと天狗のおじさんに怒られるElmアプリを作った

Last updated at Posted at 2020-12-19

はじめに

Elmのアドベントカレンダー20日目に申し込みさせていただきました。まったくElmを触らない人間が投稿するのはかなり申し訳ないのですが、書かせていただきます。
ついでにお詫びなのですが、我ながら(クオリティ含めて)クソみたいなアプリを作ってしまいました。すいませんがどうかご査証ください。

内容

妹が鬼になってしまった!そんなときに2秒以内で「闘う」か「闘わない」のどちらかを選択しないと天狗のおじさんに怒られてしまうアプリです。元ネタを知らない方は各自で調べてみると良いかと思います。

sc.png

こちらで試すことができます。

実装

まず変数として定義しておきたいのは、天狗のおじさんの回答(tenguAnswer)と2秒立ってしまったかどうか(isTimeout)の2つなのでそれぞれのモデルを定義します。

type alias Model =
    { tenguAnswer : String
    , isTimeout : Bool
    }

また、メッセージとして定義しておきたいのは判断(Decision)とその内容(Judge)なのでそれぞれを定義します。

type Judge
    = Late
    | Fast
    | Bad

type Msg
    = Decision Judge
  • Late
    • 2秒過ぎてしまった場合のメッセージ
  • Fast
    • 迷いなく「闘う」と選択した場合のメッセージ
  • Bad
    • 「闘わない」などと甘い選択をした場合のメッセージ

とりあえずそれぞれを簡単に定義しました。次に2秒すぎた場合、JavaScriptのsetTimeoutみたいなことを実装する方法がよくわからなかったので@sandさんのこちらの記事を参考に実装してみました。
その上で、モデルの定義はこんな感じで実装しました。

type alias Model =
    { tenguAnswer : String
    , isTimeout : Bool
    }


longTask : Task Never Judge
longTask =
    Process.sleep 2000
        |> Task.map (always Late)


init : () -> ( Model, Cmd Msg )
init _ =
    ( Model "" False
    , Task.perform Decision longTask
    )

このlongTaskという関数が2秒経過後にLateというメッセージを渡すようにしました。あとの実装は完全に成り行きにまかせて行ったのでコード全文貼ってしまいます。

module Main exposing (..)

import Browser
import Html exposing (Html, button, div, h1, img, text)
import Html.Attributes exposing (hidden, style, src)
import Html.Events exposing (onClick)
import Process
import Task exposing (..)



-- MODEL


type alias Model =
    { tenguAnswer : String
    , isTimeout : Bool
    }


longTask : Task Never Judge
longTask =
    Process.sleep 2000
        |> Task.map (always Late)


init : () -> ( Model, Cmd Msg )
init _ =
    ( Model "" False
    , Task.perform Decision longTask
    )



-- UPDATE


type Judge
    = Late
    | Fast
    | Bad


type Msg
    = Decision Judge


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Decision judge ->
            case judge of
                Bad ->
                    ( { model
                        | tenguAnswer =
                            if not model.isTimeout then
                                "判断が甘い"

                            else
                                model.tenguAnswer
                        , isTimeout = True
                      }
                    , Cmd.none
                    )

                Fast ->
                    ( { model
                        | tenguAnswer =
                            if not model.isTimeout then
                                "判断が早い"
                            else
                                model.tenguAnswer
                        , isTimeout = True
                      }
                    , Cmd.none
                    )

                Late ->
                    ( { model
                        | tenguAnswer =
                            if not model.isTimeout then
                                "判断が遅い"

                            else
                                model.tenguAnswer
                        , isTimeout = True
                      }
                    , Cmd.none
                    )



-- SUBSCRIPTIONS


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



-- VIEW


view : Model -> Html Msg
view model =
    div
        [style "text-align" "center"]
        [ h1 [] [ text "妹が鬼になってしまった!" ]
        , button [ onClick (Decision Fast), style "font-size" "2em" ] [ text "闘う" ]
        , button [ onClick (Decision Bad), style "font-size" "2em" ] [ text "闘わない" ]
        , h1 [ hidden (not model.isTimeout) ] [ text model.tenguAnswer ]
        , img [ src "./tengu.png", hidden (not model.isTimeout) ] []
        ]


main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view
        }

updateの処理が結構汚くなってしまいました。「2秒経過するまでにどちらかのボタンを選択するとLateというメッセージの送信がストップされる」というような実装をしたかったのですが方法がわからなかったので、if文をつかってtenguAnswerが書き換わるのを止めるという実装にしました。このあたりの良い実装方法があれば教えていただきたいです。。。

おわりに

すいません、かなりボリュームの小さい記事になってしまいました。Elmでタイマーを使った処理の実装が思ったよりも難しくて、もう少しライブラリに関しての理解が必要だなと感じた次第です。。。

11
1
0

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
11
1