強化学習 AlphaZero 17 (三目並べ AlphaZero9)

AlphaZeroで学習したモデルと人間で対戦するゲームを作成します。

必要なパッケージをインポートします。

human_play.py
1
2
3
4
5
6
7
8
# パッケージのインポート
from game import State
from pv_mcts import pv_mcts_action
from game import State, random_action, alpha_beta_action, mcts_action
from tensorflow.keras.models import load_model
from pathlib import Path
from threading import Thread
import tkinter as tk

学習したベストプレイヤーのモデルを読み込みます。

human_play.py
1
2
# ベストプレイヤーのモデルの読み込み
model = load_model('./model/best.h5')

ゲームUIのクラスを定義します。
メソッドは下記のとおりです。

  • init ゲームUIを初期化します。
  • turn_of_human 人間のターンを実行します。
  • turn_of _ai AIのターンを実行します。
  • draw_piece 石の描画を行います。
  • on_draw 描画の更新を行います。

初期化処理ではゲーム状態と行動選択を行う関数を生成し、キャンバスを用意します。

human_play.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ゲームUIの定義
class GameUI(tk.Frame):
# 初期化
def __init__(self, master=None, model=None):
tk.Frame.__init__(self, master)
self.master.title('三目並べ')

# ゲーム状態の生成
self.state = State()

# PV MCTSで行動選択を行う関数の生成
self.next_action = pv_mcts_action(model, 0.0)

# キャンバスの生成
self.c = tk.Canvas(self, width = 240, height = 240, highlightthickness = 0)
self.c.bind('<Button-1>', self.turn_of_human)
#self.c.bind('<Button-1>', self.turn_of_ai)
self.c.pack()

# 描画の更新
self.on_draw()

人間のターンの処理は下記のようになります。

  1. ゲーム終了時はゲームを初期化状態に戻します。
  2. 先手でないときは操作不可とします。
  3. クリック位置を行動に変換します。
  4. 合法手でないとき無処理とします。
  5. 次の状態を取得します。
  6. AIのターンへ遷移します。
human_play.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 人間のターン
def turn_of_human(self, event):
# ゲーム終了時
if self.state.is_done():
self.state = State()
self.on_draw()
return

# 先手でない時
if not self.state.is_first_player():
return

# クリック位置を行動に変換
x = int(event.x/80)
y = int(event.y/80)
if x < 0 or 2 < x or y < 0 or 2 < y: # 範囲外
return
action = x + y * 3

# 合法手でない時
if not (action in self.state.legal_actions()):
return

# 次の状態の取得
self.state = self.state.next(action)
self.on_draw()

# AIのターン
self.master.after(1, self.turn_of_ai)

AIのターンは下記のようになります。

  1. ゲーム終了時は無処理とします。
  2. ニューラルネットワークで行動を取得します。
  3. 次の状態を取得します。
human_play.py
1
2
3
4
5
6
7
8
9
10
11
12
13
# AIのターン
def turn_of_ai(self):
# ゲーム終了時
if self.state.is_done():
return

# 先手でない時
# 行動の取得
action = self.next_action(self.state)

# 次の状態の取得
self.state = self.state.next(action)
self.on_draw()

石の描画を行います。

human_play.py
1
2
3
4
5
6
7
8
9
# 石の描画
def draw_piece(self, index, first_player):
x = (index%3)*80+10
y = int(index/3)*80+10
if first_player:
self.c.create_oval(x, y, x+60, y+60, width = 2.0, outline = '#FFFFFF')
else:
self.c.create_line(x, y, x+60, y+60, width = 2.0, fill = '#5D5D5D')
self.c.create_line(x+60, y, x, y+60, width = 2.0, fill = '#5D5D5D')

描画を更新します。全てのマス目と石を描画します。

human_play.py
1
2
3
4
5
6
7
8
9
10
11
12
13
# 描画の更新
def on_draw(self):
self.c.delete('all')
self.c.create_rectangle(0, 0, 240, 240, width = 0.0, fill = '#00A0FF')
self.c.create_line(80, 0, 80, 240, width = 2.0, fill = '#0077BB')
self.c.create_line(160, 0, 160, 240, width = 2.0, fill = '#0077BB')
self.c.create_line(0, 80, 240, 80, width = 2.0, fill = '#0077BB')
self.c.create_line(0, 160, 240, 160, width = 2.0, fill = '#0077BB')
for i in range(9):
if self.state.pieces[i] == 1:
self.draw_piece(i, self.state.is_first_player())
if self.state.enemy_pieces[i] == 1:
self.draw_piece(i, not self.state.is_first_player())

ゲームUIを実行します。

human_play.py
1
2
3
4
# ゲームUIの実行
f = GameUI(model=model)
f.pack()
f.mainloop()

対戦状況は下記の通りです。

対戦中

何回か対戦してみましたが、それほど強いイメージはありませんでした。

参考

AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門 サポートページ