Open AI gymでオセロの強化学習環境を作成してみた

## はじめに
OpenAI gymでオセロを強化学習するための環境を作ってみました。
今後、強化学習の環境を作ってみたい人向けに参考になればと思います。
学習アルゴリズムは未実装です。これから勉強してみます。
コードはこちら
https://github.com/pigooosuke/gym_reversi

gym/envsには、デフォルトで様々な学習環境が入っています。
ちなみに、ボードゲーム系では、囲碁とhexがあります。
今回は、これらのコードを参考にして作成しました。

## 作成手順
1. gym/envs/ 以下にオリジナルの学習環境を作成する
2. gym/envs/\_\_init\_\_.py に作成した環境をデフォルト値と一緒に登録する
といった流れになります。

作成したEnvは、以下のように呼び出せるようになります。

```
import gym
env = gym.make('Reversi8x8-v0')
```

## Envファイル

### クラス説明
class ReversiEnv を作成しました
基本的にEnvには、５つのmethodを中心にコードを記述していく必要があります。
_step
ステップ数を１回分進める
(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を設定しています。

#### ゲーム終了確認
```python
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の値に制限を付けています。

#### 石を置ける候補を確認する
```python:
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
```