以前に考察した通り、強化学習でゼロから麻雀AIを学習する場合、偶然和了した際の報酬のみで役を学習するのは困難と考える。
そこで、ランダムに選択した役のN向聴の状態からゲームを開始して、補助タスクとして和了した役も学習させることにする。
今回は、N向聴の状態の初期局面を生成する処理を実装した。
N向聴の状態の生成処理
N向聴の状態は、以下の手順で生成する。
役の手牌をランダムに生成する処理
役の手牌をランダムに生成する処理は、前回の記事に記載した。
β分布からサンプリング
プレイヤーごとに向聴数をばらけさせるため、向聴数はβ分布からサンプリングする。
β分布は以下のような分布である。
平均値2のベータ分布
C++で実装する場合、標準ライブラリではβ分布を直接扱えないため、ガンマ分布から生成する。
std::gamma_distribution<double> gamma1{ avr, 1.0 }; std::gamma_distribution<double> gamma2{ max - avr, 1.0 }; const double x = gamma1(mt); const double y = gamma2(mt); const double z = x / (x + y); beta = (int)(z * max);
手牌を牌山と交換する処理
一様ランダムで選択したN枚の手牌を牌山と交換する。
その際、副露している牌も対象とする。
槓の場合は、4枚目を牌山に戻す。
実行例
上記の初期局面生成処理をcmajiangに実装した。
実行例は以下の通り。
from cmajiang import * game = random_game_state(3) [display(shoupai) for shoupai in game.shoupai]
[xiangting(shoupai) for shoupai in game.shoupai]
[2, 2, 3, 1]
向聴数に3を指定しているが、平均は3より小さくなる。
これはN向聴をN枚交換する処理で代替しているため、向聴数が変わらない牌と交換される場合があるためである。
生成された手牌を見ると1枚の字牌が残っていたりする。
実際の人間の対局では、字牌は先に捨てるだろうといった知識は反映されていない。
強化学習の初期段階で役を覚えさせるために使用して、徐々にNを増やしていき、ある程度学習したら通常の対局にするのが良さそうである。
まとめ
N向聴の初期局面を生成する処理を実装した。
準備がだいたいできたので、次は強化学習の実装に着手したい。