public override void onMyTurn() { base.onMyTurn(); if (TotalTurn == 0) { System.Console.WriteLine($"AI Turn 1"); bool isPutSuccessful = PutChess(GameDef.board_cell_length / 2, GameDef.board_cell_length / 2); RoleMgr.ChangeNextRole(); } else { MinMaxSearchCount = 0; MinMaxSearchInfo bestPosInfo = MinMaxSearch(Model, MyChessType, true, 0, int.MinValue, int.MaxValue); System.Console.WriteLine($"MinMaxSearchCount = {MinMaxSearchCount.ToString()}"); System.Console.WriteLine($"SearchHasResultCount = {SearchHasResultCount.ToString()}"); System.Console.WriteLine($"Turn: {(TotalTurn + 1).ToString()} {Name} Y = {bestPosInfo.Y.ToString()} X = {bestPosInfo.X.ToString() } Score = {bestPosInfo.Score.ToString()}"); bestPosInfo.Model.PrintBoard(); bool isPutSuccessful = PutChess(bestPosInfo.X, bestPosInfo.Y); RoleMgr.ChangeNextRole(); } }
public override void onMyTurn() { base.onMyTurn(); if (TotalTurn == 1) { System.Console.WriteLine($"AI Turn 1"); bool isPutSuccessful = PutChess(GameDef.board_cell_length / 2, GameDef.board_cell_length / 2); } else { MinMaxSearchCount = 0; MinMaxSearchInfo bestPosInfo = MinMaxSearch(Model, MyChessType, true, 0, int.MinValue, int.MaxValue); System.Console.WriteLine($"MinMaxSearchCount = {MinMaxSearchCount.ToString()}"); System.Console.WriteLine($"SearchHasResultCount = {SearchHasResultCount.ToString()}"); bool isPutSuccessful = PutChess(bestPosInfo.X, bestPosInfo.Y); } }
private MinMaxSearchInfo MinMaxSearch(Model pModel, ChessType chessType, bool isMaxLayer, int depth, int alpha, int beta) { MinMaxSearchCount++; int bestScore = isMaxLayer ? int.MinValue : int.MaxValue; MinMaxSearchInfo bestPosInfo = new MinMaxSearchInfo(-1, -1, bestScore); //Console.WriteLine($"depth: {depth} isMaxLayer: {isMaxLayer} MinMaxSearchCount: {MinMaxSearchCount.ToString()} alpha: {alpha.ToString()} beta: {beta}"); // y, x, score List <Tuple <int, int, int> > OrderPosScoreList = GetPossibleBestPosOrderList(pModel, chessType); foreach (Tuple <int, int, int> PosScoreTuple in OrderPosScoreList) { int y = PosScoreTuple.Item1; int x = PosScoreTuple.Item2; Model cloneModel = pModel.Clone() as Model; cloneModel.PutChessToBoard(x, y, chessType); bool isWin = false; bool isTie = false; int tmpScore = 0; Model tmpModel; //when anyone win or tie, stop search ConnectStrategy connectStrategy = new ConnectStrategy(cloneModel); isWin = connectStrategy.IsWin(chessType); isTie = connectStrategy.IsTie(); if (isWin) { Console.WriteLine($"win happen"); SearchHasResultCount++; MinMaxSearchInfo Info = new MinMaxSearchInfo(x, y, isMaxLayer ? int.MaxValue - 1 : int.MinValue + 1); Info.Model = cloneModel; return(Info); } if (depth == MinMaxSearchDepth || isTie) { SearchHasResultCount++; tmpScore = MyEvaluation.GetScore(cloneModel, MyChessType); tmpModel = cloneModel; //cloneModel.PrintBoard(); //Console.WriteLine($"y: {y} x: {x} score: {score}"); } else { ChessType nextChessType = Utility.GetOppositeChessType(chessType); MinMaxSearchInfo info = MinMaxSearch(cloneModel, nextChessType, !isMaxLayer, depth + 1, alpha, beta); //===== alpha beta pruning ===== if (isMaxLayer) { alpha = Math.Max(alpha, info.Score); } else { beta = Math.Min(beta, info.Score); } if (alpha >= beta) { return(info); } //=============================== tmpScore = info.Score; tmpModel = info.Model; } if (isMaxLayer) { if (tmpScore > bestPosInfo.Score) { bestPosInfo.Score = tmpScore; bestPosInfo.X = x; bestPosInfo.Y = y; bestPosInfo.Model = tmpModel; } } else { if (tmpScore < bestPosInfo.Score) { bestPosInfo.Score = tmpScore; bestPosInfo.X = x; bestPosInfo.Y = y; bestPosInfo.Model = tmpModel; } } if (depth == 0) { Console.WriteLine($"y: {y} x: {x} score: {tmpScore} depth: {depth} MinMaxSearchCount = {MinMaxSearchCount.ToString()}"); //bestModel.PrintBoard(); } } #region Not use find order list /* * for (int y = 0; y < GameDef.board_cell_length; y++) * { * for (int x = 0; x < GameDef.board_cell_length; x++) * { * List<List<ChessType>> board = pModel.GetBoardByCopy(); * if (board[y][x] == ChessType.None && IsPosNeedSearch(board, x, y)) * { * Model cloneModel = pModel.Clone() as Model; * cloneModel.PutChessToBoard(x, y, chessType); * * bool isWin = false; * * int score = 0; * * if (depth == MinMaxSearchDepth) * { * SearchHasResultCount++; * score = MyEvaluation.GetScore(cloneModel, MyChessType); * * //cloneModel.PrintBoard(); * //Console.WriteLine($"y: {y} x: {x} score: {score}"); * } * else * { * ConnectStrategy connectStrategy = new ConnectStrategy(cloneModel); * isWin = connectStrategy.IsWin(chessType) || connectStrategy.IsTie(); * * //when anyone win, stop search * //isWin = MyEvaluation.IsEndSearch(cloneModel, chessType); * * if (isWin) * { * score = MyEvaluation.GetScore(cloneModel, MyChessType); * } * else * { * ChessType nextChessType = Utility.GetOppositeChessType(chessType); * MinMaxSearchInfo info = MinMaxSearch(cloneModel, nextChessType, !isMaxLayer, depth + 1, alpha, beta); * * if (isMaxLayer) * alpha = Math.Max(alpha, info.Score); * else * beta = Math.Min(beta, info.Score); * * if (alpha >= beta) * return info; * * score = info.Score; * } * * } * * if (depth == 0) * { * Console.WriteLine($"y: {y} x: {x} score: {score} depth: {depth}"); * } * * if (isWin) * { * Console.WriteLine($"Win happen y: {y} x: {x} score: {score} depth: {depth}"); * } * * if (isMaxLayer) * { * if (score > bestPosInfo.Score) * { * bestPosInfo.Score = score; * bestPosInfo.X = x; * bestPosInfo.Y = y; * } * } * else * { * if (score < bestPosInfo.Score) * { * bestPosInfo.Score = score; * bestPosInfo.X = x; * bestPosInfo.Y = y; * } * } * } * } * } */ #endregion return(bestPosInfo); }
private MinMaxSearchInfo MinMaxSearch(Model pModel, ChessType chessType, bool isMaxLayer, int depth, int alpha, int beta) { MinMaxSearchCount++; int bestScore = isMaxLayer ? -999 : 999; MinMaxSearchInfo bestPosInfo = new MinMaxSearchInfo(-1, -1, bestScore); Console.WriteLine($"depth: {depth} isMaxLayer: {isMaxLayer} MinMaxSearchCount: {MinMaxSearchCount.ToString()} alpha: {alpha.ToString()} beta: {beta}"); for (int y = 0; y < GameDef.board_cell_length; y++) { for (int x = 0; x < GameDef.board_cell_length; x++) { var board = pModel.GetBoardByCopy(); if (board[y][x] == ChessType.None) { Model cloneModel = pModel.Clone() as Model; cloneModel.PutChessToBoard(x, y, chessType); int score = 0; BoradStatus boradStatus = GetBoardStatus(cloneModel, chessType); if (boradStatus == BoradStatus.Nothing) //沒有勝負 繼續往下找 { ChessType nextChessType = Utility.GetOppositeChessType(chessType); MinMaxSearchInfo info = MinMaxSearch(cloneModel, nextChessType, !isMaxLayer, depth + 1, alpha, beta); //--------- alpha-beta pruning --------- if (isMaxLayer) { alpha = Math.Max(alpha, info.Score); } else { beta = Math.Min(beta, info.Score); } if (alpha >= beta) { return(info); } //-------------------------------------- score = info.Score; } else if (boradStatus == BoradStatus.Winlose) { SearchHasResultCount++; score = MyChessType == chessType ? 1 : -1;//If chess is mychessType get 1 point else get -1 point } else if (boradStatus == BoradStatus.Tie) { SearchHasResultCount++; score = 0; } if (isMaxLayer) { if (score > bestPosInfo.Score) { bestPosInfo.Score = score; bestPosInfo.X = x; bestPosInfo.Y = y; } } else { if (score < bestPosInfo.Score) { bestPosInfo.Score = score; bestPosInfo.X = x; bestPosInfo.Y = y; } } } } } return(bestPosInfo); }