
RiichiLab に 参戦 しました。 RiichiLabは麻雀AIを対戦させるためのオープンアリーナ、簡単に言えば麻雀AIのための天鳳です。
RiichiLabの麻雀サーバーはWebSocket上で Mjaiプロトコル にしたがい通信します。 厳密にはMjaiを機械学習AI向けに改良したプロトコルで本家のプロトコルとは互換性がありません。 具体的には、判断が必要な局面のみ応答を要求し、判断材料としてObservationと呼ばれる盤面のスナップショット的な情報を提供します。 機械学習型のAIは、このObservationからニューラルネットワークに入力できる数値データ、すなわち「特徴量」を抽出・変換して利用します。
ですが、電脳麻将のAIはルールベースで機械学習ではありません。 Observationも特徴量も不要で、1つ1つの摸打さえわかればAIが盤面を再構築し、それを使って判断します。 幸いにもRiichiLabのプロトコルでも摸打情報は省略されておらず*1、オリジナルのMjaiプロトコルを踏襲していました。
そこで、
という手順でプログラムを開発しました。
Mjaiプロトコルと 電脳麻将のプロトコル は見た目はかなり違いますが、一問一答形式であることは同じです。 サーバーからは盤面で何が起こったかを通知します。 AIはそれに対してどのように対応するかを応答します*2。
例えば東二局を親で迎え、対面の東をポンした場合*3、打牌の通知とポンの応答は
Mjaiでは
{ type: "dahai", actor: 3, pai: "E", tsumogiri: false }
{ type: "pon", actor: 1, target: 3, pai: "E", consumed: [ "E", "E" ] }
電脳麻将では
{ dapai: { l: 2, p: "z1" } }
{ fulou: "z111=" }
となります*4。
何もしない場合の応答は、Mjaiでは { type: "none" } 電脳麻将では {} です。
通知の場合は Mjai形式 → 電脳麻将形式、応答の場合は 電脳麻将形式 → Mjai形式 に変換することで、現在の電脳麻将のAIをそのまま利用できます。 ただしリーチと開槓(カンドラ)通知だけは厄介です。 リーチは電脳麻将では
{ dapai: { l: 0, p: "m2_*" } }
だけですが、Mjaiでは
{ type: "reach", actor: 1 }
{ type: "dahai", actor: 1, pai: "2m", tsumogiri: true }
{ type: "reach_accepted", actor: 1, deltas: [ 0, -1000, 0, 0 ], scores: [ 28000, 23000, 24000, 24000 ] }
となります。 開槓については電脳麻将では応答なしですが、Mjaiでは { type: "none" } での応答が必要です。
これらを実装し npm に登録しました。
インストールするとMjai完全互換のボット mjai-diannao が利用可能になります。
Mjai完全互換ボットを作成し、実際に mjai server での動作確認*5もできたので、これをRiichiLab向けに修正します。
RiichiLabのプロトコル の大きな特徴は、判断が必要となる局面で request_action の通知が来るまで 応答を返してはならない ことです。 request_action の通知には、先に説明した observation 以外にも、応答の際に使用すべき request_id、可能な応答の一覧を示す possible_actions*6、持ち時間を示す time が含まれています。 ですが、すでにMjai完全互換ボットとして動作しているならこれらの情報は不要です。 request_action の通知が来るまで応答は返さず、request_action が来たら 直前に返すはずだった応答 に request_id を付与して返せばいいのです。 ボットからの応答に対して action_ack という通知が来ますが、何か反応できる訳ではないので無視すればいいでしょう。
こうして mjai-diannao をRiichiLab対応させ 電脳麻将 としてRiichiLabに参戦しました。 もう一つ、電脳麻将最初期のアルゴリズムで「単純牌効率にしたがい聴牌即リー、鳴きなし、オリなし」の 牌効率くん も参戦させました。 こちらはRiichiLabのレベルの定点観測になるのではないかと思います。
機械学習型AIの中で電脳麻将がどれくらい健闘できるかご注目ください👍