public GameTree MiniMax(GameTree tree, eStoneType player, int depth) { if (depth == 0) { // 自分自身を返す return tree; } else if (tree.GetEnableMoveNodes().Count == 0) // ゲーム終了 { return tree; } // 本来置きたい手を置く場合は最も評価値の高い手を // 相手の手を置く場合は最も低い手を選ぶ bool to_max = (player == tree.StoneType); int top_value = 0; const int inf = (int)(1e9 + 7); if (to_max) top_value = -inf; else top_value = inf; Dictionary<int, List<GameTree>> dict = new Dictionary<int, List<GameTree>>(); foreach (var node in tree.GetEnableMoveNodes()) { int value = MiniMax(node, player, depth - 1).GetScoreDiff(); if (player == eStoneType.White) value *= -1; if (to_max) { if (value > top_value) { top_value = value; dict.Add(value, new List<GameTree>()); } if (value == top_value) { dict[value].Add(node); } } else { if (value < top_value) { top_value = value; dict.Add(value, new List<GameTree>()); } if (value == top_value) { dict[value].Add(node); } } } // 最も良いやつからランダム int n = dict[top_value].Count; return dict[top_value][Random.Range(0, n)]; }
// ゲーム木を構成する public GameTree(Board board, eStoneType type, int pos, bool passed) { Board = board; StoneType = type; PrevPos = pos; PrevPassed = passed; enable_move_nodes_ = null; score = null; }
// 盤面に石を置いて得られる石の座標を取得する public static List <int> GetObtainStones(Board board, int pos, eStoneType type) { int x = pos % 8; int y = pos / 8; List <int> get_stones_ = new List <int>(); for (int i = 0; i < 8; ++i) { bool can = false; List <int> new_pos = new List <int>(); int j = 1; while (!can) { int tx = x + j * dx[i]; int ty = y + j * dy[i]; if (tx < 0 || tx >= 8) { break; } if (ty < 0 || ty >= 8) { break; } int index = GetChipIndex(tx, ty); if (board[index] == eStoneType.None) { break; } if (board[index] == type) { can = true; break; } // 置く new_pos.Add(index); ++j; } if (can) { foreach (var p in new_pos) { get_stones_.Add(p); } } } // 自分自身 get_stones_.Add(pos); return(get_stones_); }
// ゲームを初期化する private void InitGame() { // 初期の盤面を作る Board board = MakeInitialBoard(); // 先行後攻どっちか int player = Random.Range(0, 2); eStoneType stone = (player == 0) ? eStoneType.Black : eStoneType.White; // ゲーム木を生成する game_tree_ = new GameTree(board, stone, -1, false); }
// 実際にシミュレーションする 勝ち 1 引き分け 0.5 負け 0 // 自分相手の手はランダム public float SimulateRandomPlay(eStoneType player) { GameTree node = GameTree; int n = node.GetEnableMoveNodes().Count; while (n != 0) { node = new GameTree(node.GetEnableMoveNodes()[Random.Range(0, n)]); n = node.GetEnableMoveNodes().Count; } int ret = ReversiUtils.JudgeResult(node.Board); if (player == eStoneType.White) ret *= -1; return ret / 2f + 0.5f; }
private int SimulateRandomPlay(GameTree tree, eStoneType player) { GameTree node = tree; int n = node.GetEnableMoveNodes().Count; // ゲームが終了するまでやる while(n != 0) { node = new GameTree(node.GetEnableMoveNodes()[Random.Range(0, n)]); n = node.GetEnableMoveNodes().Count; } int ret = ReversiUtils.JudgeResult(node.Board); if (player == eStoneType.White) ret *= -1; return ret; }
// 実際にシミュレーションする 勝ち 1 引き分け 0.5 負け 0 // 相手の手法を引数で渡す public float SimulateSelectedPlay(eStoneType player, BasePlayer opponent) { GameTree node = GameTree; int n = node.GetEnableMoveNodes().Count; while(n != 0) { // 自分の番ならランダムに 相手の番なら指定した手法を用いて考える if(node.StoneType == player) node = new GameTree(node.GetEnableMoveNodes()[Random.Range(0, n)]); else node = opponent.Play(node); n = node.GetEnableMoveNodes().Count; } int ret = ReversiUtils.JudgeResult(node.Board); if (player == eStoneType.White) ret *= -1; return ret / 2f + 0.5f; }
// 現在の盤面から置くことのできる手を求める public static List <int> GetEnableHands(Board board, eStoneType next_type) { List <int> ret = new List <int>(); for (int y = 0; y < 8; ++y) { for (int x = 0; x < 8; ++x) { if (board[x, y] != eStoneType.None) { continue; } bool can = false; for (int i = 0; i < 8; ++i) { if (can) { break; } int ty = y + dy[i]; int tx = x + dx[i]; if (ty < 0 || ty >= 8) { continue; } if (tx < 0 || tx >= 8) { continue; } if (board[tx, ty] == eStoneType.None || board[tx, ty] == next_type) { continue; } int j = 2; while (!can) { int tty = y + j * dy[i]; int ttx = x + j * dx[i]; if (tty < 0 || tty >= 8) { break; } if (ttx < 0 || ttx >= 8) { break; } if (board[ttx, tty] == eStoneType.None) { break; } if (board[ttx, tty] == next_type) { can = true; } ++j; } } if (can) { ret.Add(GetChipIndex(x, y)); // 置ける } } } return(ret); }
// 次の石のタイプを取得する public static eStoneType NextStone(eStoneType type) { return((type == eStoneType.Black) ? eStoneType.White : eStoneType.Black); }