Kaggle - ConnectX(1) - 4枚そろえるボードゲーム

今回からConnect Xコンペに参加したいと思います。

Connect X

Connect Xは、ボードゲームの一種で上からコインを交互に落として、縦か横か斜めに4枚コインをそろえた方が勝ちというルールになっています。

ConnectX Getting Startedというスタート練習用のノートブックがありますのでこれを試しに実行してみます。

Kaggle環境のインストール

下記バージョンのKaggle環境をインストールする必要があるようです。

Connect Xはバージョンに依存する環境なんでしょうかね。

[ソース]

1
!pip install 'kaggle-environments>=0.1.6'

[結果]

問題なくインストールすることができました。

Connect X環境の作成

Connect X環境を作成します。

[ソース]

1
2
3
4
5
from kaggle_environments import evaluate, make, utils

env = make("connectx", debug=True)
env.render()

エージェントの作成

エージェントを作成します。

ここではサンプルとしてランダムにコインを落とす場所を決めているようです。

今後はこのロジックを実装していき勝率を上げていけばいいんですね。

[ソース]

1
2
3
4
# This agent random chooses a non-empty column.
def my_agent(observation, configuration):
from random import choice
return choice([c for c in range(configuration.columns) if observation.board[c] == 0])

エージェントのテスト

上記で作成したエージェントのテストを行います。

ただ相手のロジックもランダムにコインを落とすようなので・・・・今回はただの動作確認用です。

[ソース]

1
2
3
4
env.reset()
# Play as the first agent against default "random" agent.
env.run([my_agent, "random"])
env.render(mode="ipython", width=500, height=450)

[結果]

上記のようなボードが現れてコインが次々に落とされ、コインが4つそろったら終了になります。

アニメーションとして動くのでちょっとおもしろいです。

エージェントのテストと訓練

エージェントのテストと訓練を行います。

[ソース]

1
2
3
4
5
6
7
8
9
10
11
12
# Play as first position against random agent.
trainer = env.train([None, "random"])

observation = trainer.reset()

while not env.done:
my_action = my_agent(observation, env.configuration)
print("My Action", my_action)
observation, reward, done, info = trainer.step(my_action)
# env.render(mode="ipython", width=100, height=90, header=False, controls=False)
env.render()

[結果]

一回の動作(どの位置にコインを落とすのか)ごとに、その動作がデバッグ表示されます。

エージェントの評価

作成したエージェントを評価します。

[ソース]

1
2
3
4
5
6
def mean_reward(rewards):
return sum(r[0] for r in rewards) / float(len(rewards))

# Run multiple episodes to estimate its performance.
print("My Agent vs Random Agent:", mean_reward(evaluate("connectx", [my_agent, "random"], num_episodes=10)))
print("My Agent vs Negamax Agent:", mean_reward(evaluate("connectx", [my_agent, "negamax"], num_episodes=10)))

[結果]

ランダム選択の相手との結果と、NegaMax法の相手との結果(平均報酬)が表示されます。

ゲーム終了時に勝つと 1 が、負けると 0 が、どちらでもない場合 (引き分け・勝負がついていない) だと 0.5 が報酬として得られるとのことなので、ランダム相手にはたまたま勝ち越し、NegaMax相手には全敗したということになります。

エージェントと対戦

手動でエージェントとの対戦ができます。

[ソース]

1
2
# "None" represents which agent you'll manually play as (first or second player).
env.play([None, "negamax"], width=500, height=450)

[結果]

マス目をクリックしてみたのですが、「Processing…」と表示されたまま動作しませんでした。

提出ファイルの書き出し

提出用のファイルを出力します。

[ソース]

1
2
3
4
5
6
7
8
9
import inspect
import os

def write_agent_to_file(function, file):
with open(file, "a" if os.path.exists(file) else "w") as f:
f.write(inspect.getsource(function))
print(function, "written to", file)

write_agent_to_file(my_agent, "submission.py")

[結果]

問題なく出力されました。

提出ファイルのチェック

提出用のエージェント同士で対戦させて、提出ファイルの妥当性をチェックするようです。

なぜ妥当性をチェックする必要があるかというと、「完全にカプセル化されていてリモート実行できることを確認するため」???とのことでした。

[ソース]

1
2
3
4
5
6
7
8
9
10
# Note: Stdout replacement is a temporary workaround.
import sys
out = sys.stdout
submission = utils.read_file("/kaggle/working/submission.py")
agent = utils.get_last_callable(submission)
sys.stdout = out

env = make("connectx", debug=True)
env.run([agent, agent])
print("Success!" if env.state[0].status == env.state[1].status == "DONE" else "Failed...")

[結果]

エラーになってしまいました。

メソッドがないという意味かと思いますが、仕様の変更があったのでしょうか。

おいおい調査していきたいと思います。

一通りConnect Xの動作方法が分かったので、これから少しずつ調査・実装・改善を行っていきます。