せっかく色々教わったので、まずはリファクタから対応した
AB先生のコードを真似しつつ、自分なりに良いと思う方法も混ぜてリファクタしてみた
リファクタ
ellie-app.com
大体はAB先生の真似なので、自分で書いた部分だけ解説
Model
ライトの点灯状態
type LightMode = LightOn | LightOff
Color
で持ってもいいかな?と考えたけどSTACKERゲームとしては点灯/消灯しかないので
LightMode
で管理することにした
m*nのマス目の生成
type alias InitSize = { rowSize : Int , columnSize : Int } makePointMatrix : InitSize -> List Point makePointMatrix { rowSize, columnSize } = let rowNumList = List.range 0 (rowSize - 1) columnNumList = List.range 0 (columnSize - 1) in rowNumList |> List.map (\x -> columnNumList |> List.map (\y -> { x = x, y = y }) ) |> List.concat
let~in
記法で行列の番号リストを変数に入れておくようにした
Point
生成は結局List.map
をネストさせる方法しか思いつかなかったので、パイプを使って可能な限り括弧を減らして可読性を上げてみた
|>
で左から右に読めるようになっているので、少しは読みやすい…はず
Model
の初期化
initialModel : Model initialModel = let pointList = makePointMatrix { rowSize = 7, columnSize = 10 } in { boxList = List.map makeBox pointList }
let~in
記法でPoint
の一覧を変数に入れておくようにした
後は大体AB先生のリファクタ後ソースと同じです
今回やること
- n秒ごとに
Box
を点滅させる
guide.elm-lang.org
を参考にしました。完成品はこちら
ellie-app.com
実装解説
Browser.element
に変更
Subscriptions
を扱いたいのでelement
に変更する
update
update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of InvertLight { point, lightMode } -> let invert box = if point == box.point then { box | lightMode = invertLightMode box.lightMode } else box in ({ model | boxList = List.map invert model.boxList } , Cmd.none )
返り値型を(Model, Cmd Msg)
に変更しCmd.none
を返すようにした
initialModel
initialModel : () -> (Model, Cmd Msg) initialModel _ = let pointList = makePointMatrix { rowSize = 7, columnSize = 10 } in ({ boxList = List.map makeBox pointList } , Cmd.none )
引数にflags
を追加(使わないので_
)し、返り値型を(Model, Cmd Msg)
に変更しCmd.none
を返すようにした
subscriptions
の実装
import Time subscriptions : Model -> Sub Msg subscriptions model = Time.every 2000 Tick
2秒毎に更新するsubscriptions
を実装
Time
ライブラリが必要だったのでパッケージ追加してインポートした
subscription
から呼ばれるupdate
Tick
のパターンを定義
type Msg = InvertLight Box | Blinking Time.Posix update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of Blinking _ -> (model, Cmd.none)
とりあえず呼び出せるだけ。受け取ったtime
は使わないので_
にした
マスを点滅させる処理を実装
Blinking _ -> let blinking box = if { x = 0, y = 0 } == box.point then { box | lightMode = invertLightMode box.lightMode } else box in ( { model | boxList = List.map blinking model.boxList } , Cmd.none )
まずは仮実装なのでx=0, y=0
を点滅させるよう実装
できた🆒
まとめ
subscription
でn秒ごとの制御できるの簡単- リファクタしたら行数は増えたけどコードの見通しが良くなった
- ちょっとパイプ慣れてきた、面白い🐊(
>>
,<<
は除く)
次回は指定した範囲のマスを点滅させるを実装します
おまけ
- n*mのマス目生成は需要があると思いライブラリを探した
package.elm-lang.org
良さげならライブラリがあった
どうやって実装しているか気になってソース読んでみたけどわからんかった😇
qiita.com
こちらの記事でも紹介されているのでメジャーなライブラリなのかな?