C++で実装したコンソールオセロAI。TD(Temporal Difference)学習による自己対戦でweight(盤面評価値)を自動最適化する。
# ビルド
g++ -O2 -std=c++17 -o othello_test.exe "c++_learning\c++_learning.cpp"
# 実行
./othello_test.exe| モード | 内容 |
|---|---|
| 1 | 人間 vs AI(対戦) |
| 2 | CPU vs CPU(観戦) |
| 3 | ベンチマーク(速度計測) |
| 4 | TD学習テスト(5エポック×10試合) |
| 5 | 本格学習(パラメータ入力→自動学習) |
| 6 | 学習済weightで人間 vs AI |
各マスに固定の重み weight[8][8] を持ち、盤面のスコアを以下で計算する:
スコア = Σ (AI側の石があるマスのweight) − Σ (相手の石があるマスのweight)
初期weightの例(対称性あり):
2714 147 69 -18 -18 69 147 2714
147 -577 -186 -153 -153 -186 -577 147
69 -186 -379 -122 -122 -379 -186 69
-18 -153 -122 -169 -169 -122 -153 -18
... (上下左右対称)
角(2714)が最も高く、角の隣(-577)が最も低い。
Alpha-Beta枝刈り付きMinimax探索を使用。
- 対戦時の探索深さ:
DEPTH = 5 - 学習時の探索深さ:
LEARNING_DEPTH = 3(速度重視) - Move Ordering: weight値が大きいマスから優先的に探索し、枝刈り効率を向上
盤面を uint64_t × 2(先手/後手)で表現し、合法手生成・石反転をビット演算で高速化。
vector版: 122ms/試合 → BitBoard版: 26ms/試合(約4.7倍高速化)
| 処理 | 方法 |
|---|---|
| 合法手生成 | 8方向のビットシフト+AND/ORで一括検索 |
| 石の反転 | 反転ビットマスクを計算してXOR |
| 石数カウント | __builtin_popcountll(1命令) |
自己対戦で棋譜を生成し、連続する盤面の評価値の差(TD誤差) を使ってweightを更新する。
| 記号 | 意味 |
|---|---|
盤面 Σ weight × 石の有無) |
|
| TD誤差(次の盤面と今の盤面の評価値の差) | |
| 学習率(推奨: 0.001) | |
| feature | 特徴量(そのマスの石: +1, -1, 0) |
最終手番では:
実際の勝敗結果を教師信号として使用。
オセロ盤は8方向に対称(回転×4 × 反転×2)。学習中に崩れる対称性を各エポック後に平均化で回復。独立パラメータ数は64→10個に圧縮される。
1. 初期weightを保存
2. for epoch = 1 to N:
a. M試合の自己対戦(棋譜記録)
b. 各棋譜に対してTD学習 → weight_d更新
c. 対称性の回復(8方向平均化)
d. double→int変換して次のゲームに反映
e. 定期的にweightファイル保存
3. 最終weightを保存
4. 初期weightとの対戦で学習効果を検証
| パラメータ | 推奨値 | 説明 |
|---|---|---|
| エポック数 | 500 | 学習ラウンド数 |
| 対戦数/エポック | 50 | 1ラウンドの自己対戦数 |
| 学習率 | 0.001 | weight更新の大きさ |
| 探索深さ | 3 | 学習時の探索深さ |
| 保存間隔 | 100 | 何エポックごとにweight保存 |
| ファイル | 内容 |
|---|---|
weight_initial.txt |
学習前のweight (int) |
weight_epoch_N.txt |
Nエポック時点のweight (int) |
weight_d_epoch_N.txt |
Nエポック時点のweight (double) |
weight_final.txt |
最終weight (int) |
weight_d_final.txt |
最終weight (double) |