架空伝統ゲーム「机戦」のオンライン対戦プラットフォームである cerke_online のコード負債 (part 0.5)

この記事は筆兵無傾 Advent Calendar 2022 およびボードゲーム・パズルプログラミング Advent Calendar 2022 の 14 日目の記事です。日本時間だと遅刻ですが、カリフォルニア時間だと現在 12 月 14 日の 25 時 12 分………

えっと、ハワイ時間ってことにしておきましょう(ハワイ行ったことないけど)。それならあと 47 分の猶予がありますね。

 

 



 

前回のあらすじ

hsjoihs.hatenablog.com

  • 異世界ファイクレオネで遊ばれている(という設定の)架空伝統ゲーム「机戦」の製作を手伝っています
  • オンライン対戦プラットフォーム「cerke online」を事実上全て一人で実装しています
  • 一人で突っ走っているので端的に言ってコードがカスであり、私一人でしか書いていないので気兼ねなく強い言葉でコードを罵ることができます

過去編

現状のコードにも様々な問題があるのですが、過去のコードが抱えていた(そして今では部分的に直っている)問題の方が見た目が面白いので、今回はそれをネタにしていこうと思います。

 

(過去の負債を強い語気でネタにするのに敬体はなじまないので、以下常体で書く)

 

一年前、具体的には 2021 年 11 月 6 日に、「いよいよソースコードがマズくなってきた!そろそろ先延ばしにするのをやめ、問題に直面しなくては」という思いのもとで、ファイル間の依存関係をグラフにしてみたときの様子がこちら。

 

おしまいである。スクショ中の「うわぁ。」「どうしてこんなになるまで放っておいたんだ。」が当時の私の気持ちを如実に表している。なんなら、1 年以上経った今でも、当時これを整理してまとめを書いたときの寮のベッドの配置が脳裏にはっきりと浮かび上がる*1

どうしてこうなってしまったのか

前回の記事でも書いたように、「今となって考えれば MVC パターンを採用しておけば遥かに見通しの良い実装となった」が、「当時は Elm も React もやったことがなく」組みやすいところから行きあたりばったりに組んで雑な増改築を積み重ねていった結果であるのはもちろんなのだが、もう一つ、そもそもこの机戦というゲームにそれなりに状態遷移が多く、必然的に API が複雑にならざるを得なかった(し、初めて組んでいる際には全体像が見えず、その複雑なものをきれいに構造に落とし込むという設計をサボってとりあえず書き始めてしまった)という事情がある。

 

ちなみに、上の図で現在 GroundState や ExcitedState と名前がついている型は、2021 年 10 月当時は「A」「C」とかいうカスな命名がされていた。

 

2021 年 12 月時点でこれらを GroundState や ExcitedState へと改称することも考えたのだが、当時の私は「物理学知らないとわかんない命名とか微妙でしょ」と考え、これを一旦却下

github.com

 

この判断を改め、『そういう命名は(属人化を上げるので)「闇鍋」になると言ったが、「物理学の素養があれば分かる命名」は、「誰にも絶対に分からない命名」よりも優れている。』として GroundState / ExcitedState を採用したのは、実に翌年の 2022 年 9 月を待つことになるのであった。

 

また、上の図で青矢印の横に書いてある POST 先が全て /decision/ の形になって一貫しているのは 2021 年 12 月 4 日にリファクタリングして API を整理したからであって、それ以前の命名惨憺たるものであった。

 

github.com

 

教訓

  • 一人で開発していると、得てしてコードは闇鍋化する
  • 他人が覗いてきたり他人に見せようとしたりしない限り、闇鍋はいくらでも拡大する
  • 年に 1 回ぐらいはコードのカスさを如実に示す文書を書いて反省に資するなどする必要がある

 

よし、現在ぴったりハワイ時間の 23:59!

*1:スタンフォードは住む寮が毎年変わる

架空伝統ゲーム「ケセリマ」を Elm で実装した話

この記事はボードゲーム・パズルプログラミング Advent Calendar 2022 と Elmのカレンダー | Advent Calendar 2022 および筆兵無傾 Advent Calendar 2022 の 12 日目の記事です。

背景 part 1

(記事の技術的内容には本質的な関わりがないので、お時間のない方はこのパートは読み飛ばしていただいても構いません。)

こんにちは、hsjoihs です。

過去記事にも書いた通り、創作の種類の一つに「架空世界創作」、つまり、架空の世界の言語・文化・地理などを創作するという形態があり、ご縁あって、2017年頃から私もファイクレオネという架空世界についての創作を手伝わせていただいております。

hsjoihs.hatenablog.com

具体的には、架空世界の言語を創作し、その言語で説話を書いたりしつつ、

架空のボードゲームの細かなルール差が生んでいる社会問題をその言語で語り、

f:id:hsjoihs:20211222185515j:plain

y1 huap1 cet2 kaik zui1(官定机戦論)。机戦にある地方ごとの細かなルール差が金銭トラブルなどを生んでいる実情を重く見て、「統一規則を制定することで人々の相互尊重が期待できる」「ルールの差を論じるにも、統一規則があると便利である」といった趣旨の文章。

それを元に公式の統一ルールを整備し、それをこれまた架空世界の言語で書き、

AIL PANIT LETI CETKAIK LETI KULANTE(アイル統一机戦書)の一ページ

そのボドゲオンライン対戦バージョンを実装していたりします。

f:id:hsjoihs:20211222184715p:plain

オンライン対戦の入り口ページで、言語設定で異世界の方を選んだ場合

背景 part 2

(記事の技術的内容には本質的な関わりがないので、お時間のない方はこのパートも読み飛ばしていただいても構いません。)

さて、このように、架空世界創作というのは、ゆったりまったりダラダラと何年も続けていくことのできる趣味であり、世界というものが壮大であるがゆえに無限に続けていくことができてしまうタイプの趣味です。

それはそれでいいのですが、逆に時間を区切って「一ヶ月でどこまで架空世界創作ができるか」という方面も面白いのでは、という話が持ち上がっていました。ちょうど小説投稿サイトノベルアップ+が「異世界ファンタジー設定コンテスト」というというのを2021年6月末締切で開催していたという経緯もあり、このコンテストの趣旨にあんまりそぐわないのを重々承知の上で、我々が今までやってきた

を整備するという作業を締切厳守でやってみよう、と考えてみたのです。

novelup.plus

 

なお、「ケセリマ」という名前の由来については、これまた過去記事に書いたのですが、

hsjoihs.hatenablog.com

 

hsjoihs「この前無意味語をパッと思いつく必要が発生し、その際に「ケセリマ」でググったら一切ヒットしなかった。ラテン字表記は Queserima とかでいいか。」

SY「ケセが光という意味でリマが闇という意味です。」

hsjoihs「じゃあそれで。」

 

というスピード採用によるものです。

Elm を採用したわけ

過去記事にも書いたように、架空伝統ゲーム「机戦」のオンライン対戦では生 DOM を弄り倒すコードを書いていったので、全体像を追いづらかったという事情がありました。

hsjoihs.hatenablog.com

 

今までフレームワークを使ってのフロントエンド開発をあまりしたことがなかったという経緯があり、別の Web アプリを雑に組んでみようと思った際に「今度こそはフレームワークを使おう」と考えました。こりーさんと話した際にその旨を口にしたところ、

となりました。

そこで、2021 年 4 月 5 日の新幹線内で特にやることがなかったので、「せっかくなら前々から興味のあった Elm を学ぶか」と思い実践してみました。

その結果、The Elm Architecture がことボードゲームを書く上でかなり適しているということを実感しました。「机戦」の実装は既にコード負債がだいぶ積み重なっており、そもそもゲームそのものがかなり複雑ということもあって、現状これを別フレームワークへと移し替える目処は立っていないのですが、今回「ケセリマ」を一から実装するにあたっては Elm を使ってみようという気になりました。

採用してみての感想

幸い、中学生の頃に情報オリンピック夏季セミナーで Haskell を習っていたこともあり、基本的に特に困ることなく実装していくことができました。

また、実装する対象がボードゲームなので、Model - View - Update からなる The Elm Architecture がかなり上手く適合し、非常に書きやすかったです。

github.com

 

エスケープハッチが用意されておらず、部分関数を用いない「正しい」実装を強いられるというのも、なかなか良い体験でした。

 

ということで、Elm を使ってもう一度ボードゲームを 2022 年 3 月に実装することになるのですが、まあそれについては別の機会に話せればと思っております。

今後の展望

一方で、https://lukeplant.me.uk/blog/posts/why-im-leaving-elm/ とかを見ると、

  • 内部的で不自由な特権機構が形成されてしまっているっぽい
  • コミュニティ運営やコントリビューションに関するメタプロセスがしっかり整備されていないっぽい

(これはこりーさん言語化で、かなり私の感想と合致しているので引用させてもらう)

 

という事情があるらしく、「Elm そのものはフレームワークとしてせっかくの素晴らしさがあるのに、それを帳消ししてしまっているなぁ」という気持ちも若干……(React が Elm のいいところを上手く回収してくれているからという事情もある。書いた HTML タグをドキュメント見ながら全部 Elm の関数に手作業で翻訳していく作業を経た結果、後に React を使った際に「JSX って便利だなぁ」という感想になったし)

架空伝統ゲーム「机戦」の AI を強くするため、盤面を効率よく保持する

この記事は筆兵無傾 Advent Calendar 2022 と ボードゲーム・パズルプログラミング Advent Calendar 2022 の 7 日目の記事です。日本時間だと遅刻ですが、私はいまアメリカ合衆国にいるので遅刻ではありません(ズルい)。

 

経緯

さて、両アドベントカレンダーの 3 日目の記事である ↓ で、 id:primenumber が以下のような記事を書いてくれました。

primenumber.hatenadiary.jp

 

これをもとに作業していただいた結果、「1〜2桁くらい速くなるとできることだいぶ増えそう」と言われました。

そすうぽよ — 2022/12/04 20:43 「@hsjoihs 1〜2桁くらい速くなるとできることだいぶ増えそうなんですが、どれくらい頑張れそうな予感とかありますか?」hsjoihs — 2022/12/04 20:50
「『今月の前半は卒業のために必要な作業が存在し、その作業よりもたのしい最適化作業を頑張りすぎると、卒業のための作業が崩壊する』という点を抜きにすればめちゃめちゃ頑張れます。ところで、卒業は大事なので、今月の前半は頑張りをほどほどにするよう自らを律する必要があります」そすうぽよ — 2022/12/04 20:51「🆗🆗」

 

現状の実装は「まあ速いとうれしいけど、速さだけを求めるのは本当に速さが必要になってからでいいよね」というモチベで 2 年前に TypeScript 実装から手で移植したもののはずで、そんなに効率的な実装にはなっていませんでした。

github.com

この issue にあるように、「(将棋の角や飛車、チェスのルークやビショップのように)長距離移動する駒の動きを別の駒が妨げているかどうかを知りたい。どのマスを見ればいいか」というのを計算する関数が少し遅く、しかもこれは非常に呼ばれる回数が多いため、全体の実行時間をかなり占めてしまっていたとのことでした。

 

提案に基づきここを改善したところ、次は

そすうぽよ — 2022/12/05 02:17「 これで全体が1桁速くなるというわけではなくて、様々な最適化をがんばって2桁ぐらい速くしませんか?という話です。次のボトルネックは順にrotate board, malloc, freeですね」hsjoihs — 2022/12/05 02:19「おー、rotate_board(たしかにあまりにも多そう)の次は malloc と free がボトルネックになる感じですか。了解です」

 

これはどういうことかというと、数年前に TypeScript 実装を書いたとき、「片側から見たときの駒の動きを実装し終えた。もう片側も実装するとなると面倒なので、逆側から入力が来たら、盤面を回転させて関数を呼んで結果をもう一回回転させよう」という横着をしたのが原因で、AI が手を計算しているあいだ盤面が一生クルクルしており、そのクルクルで全体の 27.24 % の実行時間を消費してしまっていたのでした。

 

「それぐらい予見できただろ、なんで横着をしたんだ」と思われるかもしれませんが、この「机戦」というゲームは

  • 駒を踏んでそこからさらに移動する動きがあり、踏む駒の位置とそこから移動する目的地を順に指定させねばならない
  • 指し手を決める途中でサーバーに乱数を問い合わせ、それに基づき可能な手の候補を削り、クライアント側に返す必要がある
  • 到着地点が水色マスである場合、乱数を発生させ、出目不足なら指し手をキャンセル

などと、遷移する必要のある状態数がかなり多く、それらを全てバグらせずに組むのがあまりに面倒だったので、最大限に横着をしたかったのです。

 

そうは言っても、遅いせいで AI の開発の妨げになっているならよろしくない。ということで、コードを調べ、いろいろいじり、rotate_board を削除しました。

 

問題

とはいえ、そもそも速く実行できるようにすることを意識していないコードなので、それをリファクタリングしていって速度を上げていくというのにも限界があります。現状の遅い実装はリファレンス実装とし、「メモリへの優しさを最優先した構造へと書き換える」をやらないといかんという結論に至りました。

そすうぽよ — 昨日 05:29 「こっちの環境ではmalloc, cfree, ...の順になってて再現できてないんですよね」 hsjoihs — 昨日 05:52 「WSL で走らせてるのが変な影響出てるのかなぁ まあとりあえずいずれにせよ『メモリへの優しさを最優先した構造へと書き換える』をやらないといかんのは容易に想像が付きますね」そすうぽよ — 昨日 06:04 「9*9の盤面に駒を並べるデータ構造にするか、49駒それぞれの位置と状態を記憶するか」

 

49 駒それぞれの位置と状態を記憶すると、49 バイトで必ず収まるというメリットがある一方で、このゲームのゲームロジック上では「特定のマスが空きマスかどうか」を判定する機会が多く、それがいちいち面倒となるデータ構造ではよろしくないと考えました。

一方、このゲームには持ち駒の概念があります。よって、そちらについては「48 駒それぞれについて*1、どちらかの持ち駒になっているか、それともどちらの持ち駒でもないのか」を保持する、という方針にしました。

紆余曲折

諸事情*2により、空マスを表す番号は 0 にしたかったので、最初はこのような駒番号割り当てを考えていました。

 

 

この番号の振り方は、伝統的事情とコンピュータ的事情を融合させた割り当てになっています。というのも、id:yasusho1020 が手作業で机戦の駒を彫るときには以下のような工程を経るのですが、

 

この字母紙が以下のような配列になっているので、それを踏襲して順序を決めました。

また、赤黒を交互にして縦列の順で読んでいくというエンコーディングにすることで、

  • 最下位ビットで色
  • 不等式評価で役職

が手に入り、コンピュータにやさしい(素早く計算できる)、という考えがありました。

 

しかしながら、id:primenumber から「兵が1スタートでなく0スタートにした方がbit演算とか表引きとかに便利そうかなあと思いました」という意見がもたらされ、「そうだよなぁ、どうしようかな」と思っていたところ、非常に上手いアイデアが寄せられ、

 

そすうぽよ — 昨日 22:33「 兵が1スタートでなく0スタートにした方がbit演算とか表引きとかに便利そうかなあと思いました」hsjoihs — 昨日 22:39「これ迷って、Option<NonZeroU8> で書けるように 1 スタートにしたんですけど、やっぱ 0 スタートのほうがいいですかね」そすうぽよ — 昨日 22:42「64スタートにして上位2bitが0b00→どちらも動かせない(空きマス) 0b01→IASideが動かせる 0b10→ASideが動かせる 0b11→どちらも動かせる(皇)にするとかもありかも」hsjoihs — 昨日 22:42「あ〜〜上手そう 持ち駒情報の格納のしかたとも整合するわな」

これを採用することにしました。

 

結論

以下のような番号割り当てを採用することにしました。(0o は 8 進数を表す表記)

盤面に関しては 9 × 9 の空間に直に駒番号を書いていき、持ち駒に関しては、例えば下のような盤面については持ち駒を右図のように抜き出し、それぞれの枠に

  • 上向きなら 01 
  • 下向きなら 10
  • どちらでもないなら 00

という 2 桁を書き、2 進数 96 桁で 12 バイトとする、という方針に決めました。


この方法だと、盤面全体が 81 + 12 = 93 バイトに収まるだけでなく、様々な演算をビット演算で書くことができて機械にやさしいです。

 

以上の話は ↓ のリポジトリにまとめてあります。

github.com

 

今後の展望

学期末を乗り切り、冬休みに入ったら、これらをもとに可能手を爆速に列挙できるようにしたいですね。まあ既存実装をほぼそのまま移植することになりそう。

*1:49 駒のうち 1 駒は、ゲームシステム上持ち駒になることが絶対にありえない

*2:Rust で Option<NonZeroU8> が 1 バイトになるというのを使いたい

架空伝統ゲーム「机戦」のオンライン対戦プラットフォームである cerke_online の 11 月末アプデから見るコード負債 (part 0)

この記事は筆兵無傾 Advent Calendar 2022 およびボードゲーム・パズルプログラミング Advent Calendar 2022 の 2 日目の記事です。

概要

過去記事にも書いたように、2017年頃から架空世界創作というものを手伝わせていただいています。

hsjoihs.hatenablog.com

 

それの一環として、異世界ファイクレオネで遊ばれている(という設定の)架空伝統ゲーム「机戦」の製作にまつわる諸々を手伝っています。

 

(製造を委託して BOOTH で販売したりもしています。興味がございましたら是非お買い求めを)

yasusho1020.hatenablog.com

 

特に、私はこのゲームのオンライン対戦プラットフォーム「cerke online」を事実上全て一人で実装するという貢献をしています(CI などのデプロイ環境の整備と画像素材の製作以外、フロントエンド・バックエンド・依存ライブラリ含め、机戦に関するコードは全て私が独力で実装している)。

問題

そういう経緯で、一人で突っ走ってきたがゆえに、私の未熟さもあり現状非常に筋の悪い実装となってしまっています。特にフロントエンドにかなり問題があり、今となって考えれば MVC パターンを採用しておけば遥かに見通しの良い実装となったのでしょうが、当時は Elm も React もやったことがなく、生 DOM をひたすらいじる険しいコードが、5000 行以上に渡って立ち並んでいます。

 

メンテしたくないコードというのはどんどん手を出す気が下がり、実際そのせいで 8 ヶ月ほど一切手を触れないでいたがために利用者の要望に応えられてこなかったなどの経緯から、2021年 8 月から「心機一転、月に一回はコードに手を入れて、月末に毎回少なくとも 1 つ機能を足して公開しよう」と決心し、以降(たまにサボってる月もあるけど)基本的に毎月末にアプデを出すようにしています。

jurliyuuri.github.io

 

さて、つい数日前に 11 月が終わり、アドベントカレンダーの季節が始まったということで、私はいま残り 15 分もない中 12/02 分の記事を書いているわけですが、11 月が終わったということは月末アプデをしたということです。

 

今回は、アプデでの変更部分を見ることで、現状の cerke_online のフロントエンドにどのようなコード負債が埋まっているのかを見ていこうと思います。

 

github.com

 

↑ をクリックしていただくと、どのようにコード変更を加えたかが確認できると思います。ということで、そろそろ日付が変わりそうなので、この辺りで part 0 を締め、如何なる困りごとが発生しているのかについては後日の記事で具体的に説明していこうと思います。

コード書いたことのない数学科に再帰下降構文解析を仕込むというたのしい遊びをした

登場人物

hsjoihs (はすじょい) : 学部生時代は数学科と物理学科。再帰下降構文解析とか C コンパイラ自作を人に教えるのが好き。
Μίττον (みっとん) : 学部と修士が数学科。圏論とかをやっている。プログラムを書いたことがほとんどない。

概要

hsjoihs「Μίττον に再帰下降構文解析、仕込める気がしてきたな。やってみるか」

hsjoihs「私が文字列を一切書かず、Μίττον の iPad 画面共有だけを見て説明する縛りでやろうと思います」

Μίττον「如何なる問題を解くんですか?」

hsjoihs「とてもよい質問ですね。(5 + 3) * (3 - 2 + 1) みたいな式が文字列として与えられ、それに対する標準的解釈を筋よく計算したい、というモチベです」

結論

2 時間で説明が終わった

drive.google.com

hsjoihs が好んで見ている英語圏の YouTube チャンネル

経緯

ゆーちき「リスニングできるようになりたい...」
ゆーちき「なんか大学卒業してから年々リスニングできなくなってる...」
ゆーちき「海外の人のゼミ発表を聞くことが皆無になったのがだいぶ大きく効いてきていそう」

りちゃYouTube の自動生成字幕がかなり優秀で、私は英語圏 YouTube に時間を溶かしまくることでリスニング力を維持しています(ニュースのようなフォーマルな内容のリスニングにどれだけ役に立つのかは YouTube でなにを見るかに大きく依存しそうですが)」

りちゃ「維持していますって書いたけどまったく維持するためにやっているわけではないんですよね そこが最大の長所な気はする」

りちゃ「本当は YouTube に時間を溶かしていないでやるべきことは無限にあるんですが......」

わかるなぁ。


ゆーちき「英語のyoutube解説動画見始めるのは結構よさそうだと思ったので始めたい」
私「ゆーちき鯖に解説動画おすすめ用チャンネルでも立ててくれればいくらでも貼りますよ」

ということで、hsjoihs が好んで見ている英語圏YouTube チャンネルをまとめました。まとめたところ、なかなか好評で、ほえーるくん (@ransewhale) からも「ブログ記事にしてほしさある(こういう情報割と欲しい割にどこにもないので)」との意見を頂いたので、ブログにしておきます。私はわりと頻繁にこれらの動画を倍速再生をするという人生をやっています。

 

私がチャンネル登録しているのを全て貼ってもあまり意味がないので、各ジャンル 2 つまでの選定をしました。



一般受けする科学

www.youtube.com

www.youtube.com


一般受けする数学

www.youtube.com

www.youtube.com


一般受けする物理学

www.youtube.com

www.youtube.com


一般受けする情報科学

www.youtube.com

www.youtube.com


数学

www.youtube.com

www.youtube.com


物理学

www.youtube.com

www.youtube.com


化学

www.youtube.com

www.youtube.com


言語紹介

www.youtube.com

www.youtube.com

言語を紹介するチャンネルはもっと好みのがいくらでもあるんですが、「英語の」チャンネルという条件から外れるものが多く……


個別言語詳細

www.youtube.com

www.youtube.com


言語学

www.youtube.com

www.youtube.com


ちょっと古めの装置とか

www.youtube.com

www.youtube.com


レトロな電子ゲーム

www.youtube.com

www.youtube.com


土木

www.youtube.com


変則数独

www.youtube.com


チェス

www.youtube.com

日本机戦連盟教育会ログ (2022年9月16日) と、議事録レンダリング用の雑スクリプト PseudoRoku を公開します

過去記事にも書いたように、2017年頃から架空世界創作というものを手伝わせていただいているのですが、

hsjoihs.hatenablog.com

 

現状こういう問題が発生しています。

 

記念すべき最初の教育会でやった内容をまとめたので、一般公開します。

 

ということで、ログ本体はこちら。

sozysozbot.github.io

 

見ていただければわかるように、前回の記事「2022年セキュリティ・キャンプL3(Cコンパイラゼミ)の会話ログを全て公開します - hsjoihs’s diary」で公開したログと同じような見た目になっています。これは単に前回ログのために書いた 200 行ぐらいのスクリプトを流用したからです。

sozysozbot.github.io

 

そのための雑スクリプトも最近一般公開しました(セキュキャン受講生の方から「表示が綺麗ですごいなぁと思ったのですが、どういう感じで作られたのか興味がある」と言われてうれしかったというのがある)。議事録をいい感じにレンダリングしてくれるツールということで、Pseudo(疑似)Roku(ろく) という名前にしてみました*1

github.com

 

ところで、stepney141 さんからご報告を受けて知ったのですが、この雑スクリプトで作った HTML ファイルには、AndroidChromeレンダリングが崩れるという問題があるそうです。スマホのブラウザなんもわからん。有識者からのご意見をお待ちしております。

github.com

 

*1:PseudoSix という名前は既に使ってる人がいたので一応避けた