昔、「iGoogle」というWebサービスをGoogleが提供していたのをご存知でしょうか。
いわゆるMy Yahoo!みたいなサービスなんですがこれも2016年にサービス終了してるので知らない人には例え辛いですねw
要はコンテンツをカスタマイズ可能なポータルサイトです。
それでこのiGoogleでは「Color Junction」というミニゲームを配置する(遊ぶ)ことができて、自分が小学1年生の時とかに結構やってた記憶がありました。
それから10年以上、ふとそのColor Junctionをプレイしたくなり調べてみるとWabmoというサイトであの時のColor Junctionがホスティングされているのを見つけました。
ソースを覗いてみたのですが記法が結構古かったり、そもそもピースがHTMLによる描写ではなく画像なので表示がガビガビだったりと、リファクタリングの余地があるなと感じさせられました。
この程度の規模のゲームなら自分でも作ることができるのではないかと思い、Reactを使ってブラッシュアップされたColor Junctionを作ってみることにしました。
完成したもの
もしかしたらお気づきの方もいらっしゃるかもしれませんが、実はもうこのブログのサイドバーに完成したものを埋め込んでいます。2つ以上同じ色のタイルが隣り合うとくっついて塊になるので、塊をクリックして消していき、最終的にピースを0個にできるとゲームクリアです。
GitHubではOSSとしてこのゲームを公開しています。
実装する時にぶち当たった壁
塊がクリックされた時に塊を消す処理
Color Junctionは碁盤目のUIになっているので、状態は二次元配列で持つというところまでは当たり前のようにイメージできていたのですが、問題は「同じ色で隣り合うピースの一覧を取得する」という動作を実装するためのアルゴリズムがイメージできないことでした。同じ色で隣り合うピースの座標一覧が取得できれば、あとはそれを先程の二次元配列に当てはめて該当する座標のピースが持つ情報を「消された」という情報に書き換えていくだけなのですが…
という感じで困っていたところ、「Color Junctionの動作ってぷよぷよに似てないか?」というイメージが降ってきたのでぷよぷよの実装方法を調べてみることにしました。
するとこのページに行きつき「深さ優先探索」というキーワードを拾うことができました。
深さ優先探索(DFS)
DFSも最初調べたところ、概要は掴めても実装のイメージが湧かなかったのですが、このページのソースを読んだら実装のイメージが湧きました。
塊を角丸にする処理
Color Junctionのピースは角丸になっています。独立したピースなら単純な角丸の正方形として描写すれば良いのですが、それ以外の場合ピースの配置によってピース(四角形)のどこが角丸になるのかが変わるのでそれを条件分岐させる必要があります。なのでまずはその条件を列挙するために、先程のWabmoでホスティングされているColor Junctionを参考にしながら角丸のタイプを列挙しました。この画像の右側では色々書いていますが、結局alignedX
より下は使いませんでした。
実際のコードに落とし込む時にList index out of range
を避けるためにこのような全列挙の書き方になってしまったのですが、これもっとスマートに書く方法無いですかね。代替案お持ちの方はプルリク送ってくれるとありがたいです!
境界を埋める処理
Color Junctionでは、それぞれのピース同士が間隔を空けて配置されていますが、同じ色がくっついて隣り合った場合、塊になるので間隔を埋めなくてはいけません。
そこで、ピースとピースの間に更にHTMLの要素(div)を設けて、左右同士が同じ色、もしくは上下同士が同じ色だった場合その要素のbackground-colorを同じ色にするという描写方法にしています。
この画像の赤線と青線が新たに設けたdivです。開発中なので分かりやすく全て同じ色で色付けしてますが、ゲームプレイ中はこの線の色が動的に変化するということです。
先程の角丸にする処理もですが、この「色を動的に変化させる」という処理にもDFSを使っています。
消されたピースの分を詰める処理
Color Junctionは塊を消すと、消した分ピースが下に詰められるのですが(1列消すと1列分左に詰められる)、このアルゴリズムが思いつかなかったので話題のChatGPTに考えてもらうことにしました。
このように入力と出力と言語を指定すると一瞬でアルゴリズムを考えてくれます。
修正依頼も、要件を話すと正確に内容をピックアップしてくれます。
前々から何回かChatGPTとは雑談していてその凄さは十分わかっていたのですが、やはりこんなに実用的なペアプログラミングの相手がいると考えると、更にヤバさが際立ちます。
あとがき
自分で何回もプレイしているうちにコツが掴めてきました。
まず右下の方から消していって、全体の半分ぐらい消し終わったら次に左下の方から消していくとクリアできる確率が高いです。
コメント