麻雀AIを作ってみたいという人にとっての最大の障壁は「AIの対戦の場を作ること」ではないでしょうか? 電脳麻将 を使えば
- AIと画面上で対戦
- AI同士をCLIで対戦
- AIのボットを麻雀サーバーに接続して対戦
という形で対戦の場を作ることができます。
ツモ切りAIの実装
まずは一番簡単なツモ切りAIを実装して対戦してみましょう。まず @kobalab/majiang-ai を clone します。
$ mkdir work $ cd work $ git clone https://github.com/kobalab/majiang-ai.git $ cd majiang-ai $ npm ci
次に lib/player.js を以下の7行の実装に変更します。
const Majiang = require('@kobalab/majiang-core'); module.exports = class Player extends Majiang.Player { action(msg, callback) { if (callback) callback({}); } }
これだけです。電脳麻将の対戦インタフェースでは、たった1つのメソッド action(msg, callback) を使います。msg は 通知メッセージ であり、callback で指定された関数を使ってこれに対応する 応答メッセージ を返すことで局が進行します。この実装では常に「空応答」{} を返しているので、ゲーム進行側でデフォルトの動作(ツモのときはツモ切り)を選択します。独自のAIの実装を行う場合は、メソッド action() を改造し、適切な応答を返すようにすればよい訳です。
では、このAIを画面上に登場させましょう。電脳麻将 を clone します。
$ cd .. $ git clone https://github.com/kobalab/Majiang.git $ cd Majiang $ npm ci
先ほど修正した麻雀AIに置き換えます。
$ npm i ../majiang-ai
ビルドします。
$ npm run release
ブラウザから dist/index.html を開けばツモ切りAIと対戦できます。
電脳麻将のAIをベースに実装
メソッド action() を修正すればAIを実装できますが、ゼロから実装するのは大変です。電脳麻将の既存のAIをベースに改造すれば比較的簡単にAIを実装できます。
majiang-ai/legacy に既存のAIがあるので、これをベースに修正を加えます。各AIの特徴については README を参照してください。「電脳麻将本」にはさらに詳しい解説があります。
ここにあるAIはすべて以下のメソッドを実装することで実現しています。逆に言えばこれらのメソッドの判定基準を変更すれば、あなたなりのAIを実装できるということです。
- select_hule()
- 和了するか否か。
- select_pingju()
- 九種九牌で流局させるか否か。
- select_fulou()
- 副露するか否か、副露するならどの面子で副露するか。
- select_gang()
- 暗槓・加槓するか否か、カンするならどの面子でカンするか。
- select_dapai()
- どの牌を打牌するか。
- select_lizhi()
- リーチするか否か。
- select_daopai()
- 流局時にテンパイ宣言するか否か。
ゼロから開発したい場合は player-0000.js をベースにすればよいでしょう。上記のメソッドがすべて空の実装となっています。
これらの電脳麻将の実装をベースにする場合は this.model に自分の手牌や相手の河などの 卓情報 が設定されるので、これを判断に利用することができます。
AIの評価
作成したAIの強さを評価するために、CLIでAI同士を対戦させることができます。AI自動対局スクリプト で3名の既存最新AI(0504)と作成したAIを対戦させるには以下とします。
$ node dev/testplay.js 0504
CLIなので対戦の様子は見えませんが、結果を牌譜に保存できるので、保存した牌譜を 牌譜解析ツール で解析したり、牌譜ビューア で再生できます。麻雀は運の要素が大きいため、同じアルゴリズムのAI同士を対戦させても1000半荘の対戦では平均順位は 2.45~2.55 程度にばらついてしまいますが、デュプリケート対局 の機能を使えば同じ牌山、同じツモで対戦できるため、強弱の判定がしやすくなるでしょう。
実際にAIを作成し、評価し、成長させていく様子は「電脳麻将本」でも詳しく解説しています。
ボットの作成
作成したAIをボット化して麻雀サーバーに接続することもできます。以下の記事で解説していますのでご参照ください。