TL;DR
将棋の定跡を学習するための「ShogiTree」というWebアプリを作りました。
この記事では、開発日誌的なテイストでShogiTreeについて共有したいと思います。
背景 | 将棋の本は難しい
将棋の本には、次のように符号を駆使した文章が現れることが多々あります。
☖9三同玉は☗8五桂(変化図18)と打てば、 ☖9ニ玉は☗9九香☖8ニ玉☗9ニ飛から後手玉が詰むし、☖8ニ玉は☗9三角の打ち込みが厳しく先手勝勢となる。
いかがでしょうか?読者は盤面図を見ながら定跡を学ぶことになりますが、非常に分かりにくいですよね。頭の中で駒を動かしながら盤面の変化を理解する必要があり、将棋を始めたばかりの人には難解です。
また、定跡には「相手がこう指してきた場合は、自分はこう指せば良い」といった条件分岐が多く、本を使った定跡の学習や暗記は難しいと思われます。
解決策
将棋の定跡を反復的に学習し、盤面の変化を視覚的に捉えることができるツールを作成しました。
以下のページから利用可能です。
上記の図は、作成したアプリケーションのデモンストレーションでして、
盤面の駒を操作することによって、盤面の変化が樹形図として可視化されます。
また、盤面の操作するダイアログから「棋譜暗記用リンク」が利用可能でして、
棋譜を反復的に暗記するためのトレーニングが可能です。
因みにですが、「棋譜暗記用リンク」の遷移先は、以前Qiita記事でも取り上げた「棋譜暗記Web」になります。
https://qiita.com/tobita_yoshiki/items/068ced648b59af656d1d
技術的なところ
採用言語
TypeScriptを使った開発が無難かとも思いましたが、
イミュータブルな変数や高階関数を駆使したコーディングスタイルが好きなので、
私が普段業務で使用しているScala言語を採用しました。
採用ライブラリ
React Flow
グラフ描画のUIが美しいという理由でReact Flowを採用しました。カスタマイズ性も高く、樹形図の描画をライブラリに任せることもできるので、今回のユースケースにはピッタリだと思いました。
余談ですが、樹形図を綺麗に描画するアルゴリズムは大変奥が深いようです。木を描画する際、ある子要素によって構成されるサブツリーと別の子要素によって構成されるサブツリーが重ならないようにするという難しい課題があります。
参考:
slinky
slinkyとは、ReactアプリケーションをScalaで開発するためのライブラリです。
React Flowを使用するために導入しました。
ScalablyTyped
ScalablyTypedは、TypeScriptの型定義をScala.jsプロジェクトで利用できるように変換するツールです。これにより、TypeScriptの型定義を持つJavaScriptライブラリをScala.jsプロジェクトで型安全に利用することができます。
実際に使ってみたところ、TypeScriptの型定義をScala側に取り込めないケースもありますが、自前でJavaScriptのラッパーを書く必要がないので非常に便利でした。
デプロイ先
Netlifyにデプロイしました。
せっかく作ったので shogitree.com というドメインを取得しました。
生まれて初めてドメインを取得しましたが、Netlify上で画面を操作してクレジットカード情報を入力するだけで簡単に取得できました。思ったより簡単に取得できて、少し高揚しました🤩
苦戦したところなど
実は将棋のルールは多い
開発当初はオセロより若干複雑そうだなぐらいにしか思っていなかったですが、
ルールを洗い出していくと、かなりルールが多いことに気づきました。
例えば、以下のようなビジネスルールがあります。
- 駒によって動ける場所が異なる
- 「飛車, 龍, 角, 馬, 香車」問題
- どれも一直線に動ける駒だが、相手の駒があるところまでしか進めない
- 自分の駒があるとその一歩手前で止まる必要がある
- 相手の成駒を取ると、成る前の状態で持ち駒に加わる
- 相手の陣営に入ると成れる/相手の陣営内にある駒を動かすと成れる
- 持ち駒を相手の駒の上に打てない
- 最上段に香車や歩を移動させる場合に必ず成る必要がある
- その他、禁じ手
- 手間だったのでShogiTreeではバリデーション等は実装していないですが、二歩や打ち歩詰め、王手放置などがあります
JavaScriptをラップする問題
ScalablyTypedを使って補助的に型情報を取ることができますが、JavaScriptライブラリによっては型情報を取得できず、自前でJavaScriptをラップする処理を書く必要があります。
また、JavaScriptライブラリをラップする際にasInstanceOf
のような危険な処理が多く出てくるため、この辺りも気になります。
TypeScriptを用いた開発と比べるとコンパイルが遅い
これはScalaの問題から受け継いだものですね。
デバッグの問題
React、JavaScript、TypeScriptの型定義(ScalablyTyped)、Scala.jsなど、多くの依存関係があるため、問題が発生したときにどのレイヤーで問題になっているか特定する必要がありました。
Scala.js越しにReactを遠隔操作している感覚があり、デバッグ時に苦戦することがありました。
総括
JavaScriptをラップする問題や依存関係の多さなどの課題はありましたが、総じて開発者体験は良かったです。日頃Scala以外の言語で開発する際、Scalaならこう書けるのにと思うことが多々ありますが、それがないのは快適でした。
全体的に、Scala.jsを使った開発はまだ発展途上だと感じており、今後のエコシステムの発展に期待しています。(余力があれば自分でOSSにコミットします)
追記: 2024/11/04
Firebaseにサイトを移行しました