フォルダ整理していたら、二年ほど前に書いたOCaml用の麻雀ライブラリが発掘されました。
しまっておくのも無駄だし、バックアップも兼ねてgithubに上げておくことに…
https://github.com/tategakibunko/ocaml-mjlib
一応、ゲームやプレイヤーなども含めて抽象化されている(っぽいけど忘れた)。
ちゃんとユニットテストも付いてるから、それなりに動くんだと思います。
縦書き文庫では、ろくにテストもせずに上げ、苦情ドリブンで対応する僕ですが(個人的にソーシャルデバッグと呼んでいる)、 こういうロジック系のライブラリでは流石にユニットテストぐらいは書きます。
ちょい見る限り、どこか抜けはあるかもしれませんが、日本ルールの役は一通り得点計算できてる(はず)。
ちなみに、よくブログ記事で麻雀の処理を書いてみた、みたいなので、アマタ、シュンツ、コーツをパースして「はい、おしまい」みたいな人をよく見かけますけど、それって麻雀全体の得点計算ロジックの1割にも満たない部分ですからね。
というのも、麻雀って、手元にある14牌の状態だけで判断できる役とか得点なんて殆どないのです…
得点を正しく計算しようと思ったら、とにかく色々なコンテキストを検証する必要があるので。
まずそもそも手元の14牌だって、最後の一枚がツモなのかロンなのかってので区別する必要がありますよね。
ツモかつ喰いがなければ「ツモ」なる役が付くわけですし。
さらにプレイヤー同士の席順で判断する必要のある役とか点とかルールもあるから(リーチ一発とか、ダブロンとか、チーはカミチャだけとか)プレイヤーを抽象化する必要もあるし。
面子だって、鳴かれたものなのかどうかで府の計算も変わるし、役の扱いも変わってくるし(じゃなきゃ、ただのトイトイがスーアンコになってしまう)。
また上がる前の「待ち」がどうだったかによって付く役と付かない役とか符もある。
リャンメン待ちじゃなけりゃピンフにならないし。
リャンメンじゃないならないで、そういう場合は待ちには符がついて得点が変わるし。
また場風で決まる役もあるから(風牌とかダブトン、ダブナンとか)、ゲームの進行状況も抽象化しないと正しい得点計算が出来ない。
他にも裏ドラとかリンシャンとかハイテイとかチョンボとか…まあ色々です。
とにかくゲームの状況(コンテキスト)で決まるものが多すぎるので、必然的に色々なものを抱え込んで抽象する必要があるわけです。
例えばカレンダーを扱うライブラリだってそうですよね。
単に暦とか言ったって、見る観点が色々とあるので。
時間として扱うのか、日付として扱うのか、それともある日付を基準として数えた現在までの秒数として扱うのか。表示フォーマットだって、国ごとに色々あります。
麻雀ライブラリもそういう感じです。
ちなみに麻雀ゲームは過去に色々な言語で作ったことがあるのですが(個人的な趣味です)、 一番楽に書けたのはOCamlだったと思います。
過去の組み合わせは、サーバー/クライアントの組み合わせで
とかです。
まあ経験値が上がったぶん、最新のものが楽になってるのは当然かもしれないですけど。
これ以外には、Haskellの自習用で作った簡易麻雀ライブラリ(hml)もありますが、HaskellもOCamlと同じぐらい書きやすかったかもです(特にShowって型クラスが便利だった)。
ちなみにこのライブラリ、最近になって妙にforkされているのですけど、Haskellの手習いとして作ったものなので純粋にヘタクソだし、そもそも大きな山の一割ぐらいしか上っていないので「いいんかな?」という感じです。