はじめに
OpenAI gymでオセロを強化学習するための環境を作ってみました。
今後、強化学習の環境を作ってみたい人向けに参考になればと思います。
学習アルゴリズムは未実装です。これから勉強してみます。
コードはこちら
https://github.com/pigooosuke/gym_reversi
gym/envsには、デフォルトで様々な学習環境が入っています。
ちなみに、ボードゲーム系では、囲碁とhexがあります。
今回は、これらのコードを参考にして作成しました。
作成手順
- gym/envs/ 以下にオリジナルの学習環境を作成する
- gym/envs/__init__.py に作成した環境をデフォルト値と一緒に登録する
といった流れになります。
作成したEnvは、以下のように呼び出せるようになります。
import gym
env = gym.make('Reversi8x8-v0')
Envファイル
クラス説明
class ReversiEnv を作成しました
基本的にEnvには、5つのmethodを中心にコードを記述していく必要があります。
_step
ステップ数を1回分進める
(playerの差し手とopponentの差し手を出力し、ゲームが終わっていないかを確認)
_reset
Envの初期設定を読み込み
(ボードの読み込み、先行後攻など)
_render
EnvのStatusを図示する(画像、RGB、テキストがセットされている)
(ボードの石の状況を表示)
_close
Envの情報をすべて破棄する
(今回は未使用)
_seed
random seedによりactionを決定するのに利用
(設定)
classのinit
初期値には、
player_color: プレイヤーの石の色(黒が先)
opponent: opponentの戦略(今回はランダム)
observation_type: State encoding (不要な設定?消してもいいかも。numpy3cでstatusを管理していますという宣言。一応残している)
illegal_place_mode: ミスプレイをしたときの罰則(負けなど)
board_size: ボードのサイズ(今回は8)
を設定しています。
action
actionはEnvに対して、どの行動をとるかを決めます。
8x8のボードなので、0-63が打ち手の位置、64が投了、65がpassを設定しました。
actionの部分に強化学習の出力を導入するイメージです
done
step処理の後半にこのstepの結果、ゲームが終了しているか確認する必要があります。
- 石を置く場所がない。
- どちらかのプレイヤーの石一色になってしまった。
という条件に合致した場合、
ゲーム終了とともに、rewardを返します。
reward
評価方法は勝ち負けの1,-1を設定しています。
ゲーム終了確認
def game_finished(board):
# Returns 1 if player 1 wins, -1 if player 2 wins and 0 otherwise
d = board.shape[-1]
player_score_x, player_score_y = np.where(board[0, :, :] == 1)
player_score = len(player_score_x)
opponent_score_x, opponent_score_y = np.where(board[1, :, :] == 1)
opponent_score = len(opponent_score_x)
if player_score == 0:
return -1
elif opponent_score == 0:
return 1
else:
free_x, free_y = np.where(board[2, :, :] == 1)
if free_x.size == 0:
if player_score > (d**2)/2:
return 1
elif player_score == (d**2)/2:
return 1
else:
return -1
else:
return 0
return 0
失敗ネタ
最初ルールを全く設定せず、どのステータスでもactionで0-63を取れる(どこにでも石を置ける)という設定をし、ルール自体を学習させようとしましたが、開始1,2手の学習で収束してしまい上手く学習できず、actionの値に制限を付けています。
石を置ける候補を確認する
def get_enable_to_actions(board, player_color):
actions=[]
d = board.shape[-1]
opponent_color = 1 - player_color
for pos_x in range(d):
for pos_y in range(d):
if (board[2, pos_x, pos_y]==0):
continue
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if(dx == 0 and dy == 0):
continue
nx = pos_x + dx
ny = pos_y + dy
n = 0
if (nx not in range(d) or ny not in range(d)):
continue
while(board[opponent_color, nx, ny] == 1):
tmp_nx = nx + dx
tmp_ny = ny + dy
if (tmp_nx not in range(d) or tmp_ny not in range(d)):
break
n += 1
nx += dx
ny += dy
if(n > 0 and board[player_color, nx, ny] == 1):
actions.append(pos_x*8+pos_y)
if len(actions)==0:
actions = [d**2 + 1]
return actions