はじめに
この記事は、「Flutter Advent Calendar 2021」16日目の記事です。
昨日の記事は、 @miyakeso さんの「表示・非表示系のWidgetの使い分けを考えてみる Visibility vs Offstage vs Opacity vs Collection If」でした。
さて、2021年も色々なことがありました。
今年は東京オリンピック開催に、ガッキーの結婚、Facebook社がMeta社になったりと、色んな出来事が盛りだくさんでした。
中でも記憶に新しいのは、棋士の藤井聡太さんが最年少で四冠を達成したことではないでしょうか?
将棋が強いと知的でかっこいいです。
かっこいいので私も将棋がやりたくなります。
将棋がやりたいので、せっかくなら将棋アプリを作ってみます。
なお、開発はFlutterで行い、状態管理にはRiverpodを使います。
また、先に、完成イメージを共有しておきます。
前提
FlutterとRiverpodは、それぞれ次のバージョンを使っています。
- Flutter 2.5.3
- flutter_riverpod 1.0.2
また、本記事では、将棋アプリの「設計」「実装」と分けて説明をしていきます。
設計
それでは、将棋アプリを設計していきます。
アプリの設計は、次の手順で行います。
- 要件定義
- 要件からオブジェクト(プログラム上で表現すべきクラス)を抽出
- オブジェクトを用いてゲームを表現するための、アーキテクチャを検討
要件定義
要件定義、というと大袈裟ですが、将棋アプリに必要な機能(将棋アプリでは何が出来れば良いか?)をツラツラと書いていきます。
- プレイヤー同士で、交互に駒を動かす
- 相手の駒を取ったら、自身の持ち駒にする
- 相手の陣地に進んだ駒は、成ることができる
- ...
要件からオブジェクトを抽出
要件を書き終わったら、要件から名詞(オブジェクト)と動詞(アクション)を抽出します。
そうすると、将棋は次のようなクラス図で表現できそうです。(厳密には、駒が各方向へ「何マス進めるか」などの情報も必要ですが、ここでは説明簡略化のために省略します)
なお、ここでは、将棋を2人のプレイヤーが交互に駒をやり取りし、どちらかが王を失う(または二歩など反則をする)まで続くゲームとして捉え、これらを表現するアーキテクチャを考えます。
オブジェクトを用いてゲームを表現するための、アーキテクチャを検討
それでは、ここまでにあげたオブジェクトを使い、将棋を表現するためのアーキテクチャを考えます。
結論から述べると、次のようなアーキテクチャを考えました。
やや一般的な名前付けとは異なりますが、基本的にはクリーンアーキテクチャチックな設計にしています。
簡単に各モジュールの役割を説明します。
- View … 画面表示
- ViewModel…状態値を表示用に加工
- State…状態値
- Repository…データ、状態値の源泉
- Command…ユースケース(駒を動かす、持ち駒を打つ、など)
- Game…ゲームの進行を管理
- Presenter…ダイアログ表示など
- Rule…ゲームの勝敗や、二歩などゲームルールに関する判定
- Model…オブジェクト置き場
なお、RepositoryとStateを一つにまとめる(Repositoryにデータ操作だけでなく、状態値をキャッシュする役割も持たせる)部分は、Flutterについて日頃から有益な情報を発信してくれている mono さんの書き方を見て、良いなと思い取り入れました。
元々、MVVM的な各画面に紐づくViewModelが状態値を保持する構成だと、状態値の取り回しが辛い(画面Aで画面Bに紐づくViewModelが保持する状態値を参照したい場合など)と感じていました。
ですが、Repositoryが状態値をキャッシュしてくれる(状態値はViewModelでなくRepositoryから参照する)なら、そうした点は解消されそうです。
また、RepositoryをSSOT(Single Source of Truth)とし、適時Riverpodで状態値を加工していけば、リアクティブ(状態値の更新に応じて、即応的に表示が切り替わる)な画面表示も実現しやすく、Flutterの宣言的な表示ロジックとも相性が良くて良い感じです。
実装
実装については、次のGitHubリポジトリへコードを載せています。
コードは2000行ほどです。
実装については、特筆すべきポイントはないため、説明は割愛させていただきます🙏
まとめ
本記事では、FlutterとRiverpodを使って将棋アプリを作りました。
よりリアルタイム性が求められるゲームならば、最近1.0.0になった 「Flame」などを使う必要があるかもしれませんが、ボードゲームくらいであれば、サクッと標準のWidgetで作れてしまうのが、Flutterの良いところですね。
2021年もほぼFlutter専業で仕事をしてきましたが、まだまだ飽きる気配がないので、2022年もFlutter漬けで頑張りたいと思います💪