TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

麻雀AIを深層強化学習で作る その7(初期局面からランダムプレイ)

前回作成した初期局面生成処理で生成した初期局面から、ランダムにプレイしても和了できるか確認を行った。

深層強化学習ではモデルが初期値の状態ではランダムに近いため、ランダムでもある程度和了できると学習の効率的に学習できる。

初期局面からランダムプレイ

初期局面を生成して、合法手をランダムに選択して、和了/流局までプレイするスクリプトを作成した。
3向聴の初期局面から終局までプレイすると、数回に1回は和了することが確認できた。

from cmajiang import random_game_state, Status, Message, xiangting
import random

n_xiangting = 3

# 初期局面生成
game = random_game_state(n_xiangting)
print([str(shoupai) for shoupai in game.shoupai])
print("xiangting", [xiangting(shoupai) for shoupai in game.shoupai])
print("lunban", game.lunban)

# 和了/流局まで繰り返す
while game.status not in (Status.HULE, Status.PINGJU):
    match game.status:
        case Status.ZIMO | Status.GANGZIMO:
            if game.allow_hule():
                # 和了
                game.reply(game.lunban_player_id, Message.HULE)
            else:
                dapai = game.get_dapai()
                # 立直
                dapai.extend(p + '*' for p in game.allow_lizhi()[1])
                p = random.choice(dapai)
                game.reply(game.lunban_player_id, Message.DAPAI, p)
        case Status.DAPAI:
            # 他家の応答 ロン、副露
            for player_id in range(4):
                if player_id == game.lunban_player_id:
                    continue
                player_lunban = game.player_lunban(player_id)
                if game.allow_hule(player_lunban):
                    # ロン
                    game.reply(player_id, Message.HULE)
                else:
                    # 副露
                    mianzi = [None]
                    mianzi.extend(game.get_chi_mianzi(player_lunban))
                    mianzi.extend(game.get_peng_mianzi(player_lunban))
                    mianzi.extend(game.get_gang_mianzi(player_lunban))
                    m = random.choice(mianzi)
                    if m:
                        if len(m) > 5:
                            game.reply(player_id, Message.GANG, m)
                        else:
                            game.reply(player_id, Message.FULOU, m)
        case Status.FULOU:
                dapai = game.get_dapai()
                p = random.choice(dapai)
                game.reply(game.lunban_player_id, Message.DAPAI, p)
        case Status.GANG:
            for player_id in range(4):
                if player_id == game.lunban_player_id:
                    continue
                player_lunban = game.player_lunban(player_id)
                if game.allow_hule(player_lunban):
                    # ロン(槍槓)
                    game.reply(player_id, Message.HULE)
    for l in range(4):
        reply = game.get_reply(l)
        if reply.msg != Message.NONE:
            print(l, reply.msg, reply.arg)
    game.next()

print(game.status)
[display(shoupai) for shoupai in game.shoupai]
if game.status == Status.HULE:
    print(game._defen)
    print(game.fenpei)
    game.next()
    print(game.defen)
['m405589p78z22,m888-', 'p577s1122337889', 'm266s244z4555667', 'm1p199s123477899']
xiangting [1, 1, 2, 2]
lunban 2
0 Message.FULOU z222=
0 Message.DAPAI p8
1 Message.DAPAI s8
2 Message.DAPAI m6
3 Message.DAPAI s8
0 Message.DAPAI z1_
1 Message.HULE 
Status.HULE

門前清自摸和	1翻
平和	1翻
一盃口	1翻
ドラ	1翻
20符 4翻 5200点

[-2600, 5200, -1300, -1300]
[30200, 23700, 23700, 22400]

まとめ

強化学習の準備として、N向聴の初期局面からランダムプレイして和了できることを確認した。
次は、モデルを使用してエピソードを収集する処理を実装したい。