趣味でプログラミングしていましたが、Elmを勉強しタイピングゲームを作ったので記事を書いてみたいと思いました。
よろしくおねがいします。
これが作ったものです
追加の別バージョン
適当に試してみてください!
Elmの難しさ
正直、自分は難しいと思いました。
関数型プログラミング言語に触れるのは初めてでそれが理由かどうかはわかりません。
うまく説明できないのですが、型です。
数学の公式をわけもわからず使って、調べてみたら難解だったというのと似てる気がします。
コンパイルエラーがたくさん親切に出てくれるので、慣れてしまおうと愚直にすすめることにしました。
恥ずかしながらいまだにHtml.mapのサンプルなどが理解できていません。
タイピングゲームの難しさ
パターンが多い
簡単なものなら「sushi」と表示させそれをそのまま入力させればいいのですが、「し」を「si」と入力したい人は困ってしまいます。
「ん」の処理となると「nn」「xn」「n」と3パターンの入力方法があります。
「ん」は厄介で、「んこ」だと「nko」で打てるのですが、「んよ」などは「nyo」では打てません。
「んっこ」だとこの3文字で30パターンくらいになります。
テストを早めに作る
パターンが多すぎて手で入力できるか試してられないので、「これは入力可能」だから成功しなければならない、「これは入力不可能」だから失敗しなければならない、というものを簡単なものから追加していきました。
Google日本語入力
google_input
この方法を知ったおかげでタイピングゲームを作ってみようという気になりました。
これと「基礎からわかる Elm」が出版されたことで開発が始まりました。
ありがとうございます。
実際には自分の理解が足りないのか苦労が多かったです。
高速化などは考えず実装しましたが、今のところ自分には問題ないように見えます。
これがコードになります
ElmでSPA
SPAにする必要はあるのかとも思いましたが、勉強にもなるということでチャレンジしてみました。
どのような構造がいいのか変わって行き苦労しました。
共通情報をどうするか
各ページ共通で利用するかもしれないデータをどうするか悩みました。
type alias Model =
{ env : Env
, page : Page
}
このenvを各ページのinitとupdateに引数で渡してしまうことにしましたが、viewには渡していません。
理由があるわけではありません。
良い設計かどうかわからず、たぶんまた変わります。
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
-- 略
( TypeLongWordMsg subMsg, TypeLongWordPage subModel ) ->
let
( newModel, topCmd, newEnv ) =
Page.TypeLongWord.update subMsg subModel model.env
in
( { model | env = newEnv, page = TypeLongWordPage newModel }
, Cmd.map TypeLongWordMsg topCmd
)
-- 略
Parser
そのまま使うことはできそうですが型が追えなくてあきらめました。
かわりにfragmentで代用してしまうことにしました。
goTo : Url.Url -> Model -> ( Model, Cmd Msg )
goTo url model =
let
pEnv =
model.env
env =
{ pEnv | url = url }
in
case env.url.fragment of
Just "post" ->
-- 略
しかし、後でクエリーからデータを取りたくなりページ内で結局使い「しまった」と思いました。
困りごと
現在あきらめてますが、ページが切り替わるとデータが消えてしまうということに気づきました。
編集ページ -> 別のページ -> 編集ページ(消えてる)
Urlでなく、ページからページへ直接データを渡すのもどうしようと悩んでいます。
おしまい
愚直に進め過ぎで、Elmの真髄に触れていないままかもしれません。
かなり苦労もありました。
しかし最も好きな言語になりそうなので、さらにElmを勉強していきたいと思います。
ここまで読んでいただきありがとうございました。