private int EvaluateBoard(Board board) { DiscColor color = this.Player.Color; DiscColor oppositeColor = DiscColor.GetOpposite(this.Player.Color); List <int[]> oppositePlayerPossibleMoves = this.GetPossibleMoves(board, oppositeColor); List <int[]> possibleMoves = this.GetPossibleMoves(board, color); if ((possibleMoves.Count == 0) && (oppositePlayerPossibleMoves.Count == 0)) { int result = board.GetDiscsCount(color) - board.GetDiscsCount(oppositeColor); int addend = (int)Math.Pow(board.Size, 4) + (int)Math.Pow(board.Size, 3); // because it is a terminal state, its weight must be bigger than the heuristic ones if (result < 0) { addend = -addend; } return(result + addend); } else { int mobility = this.GetPossibleConvertions(board, color, possibleMoves) - this.GetPossibleConvertions(board, oppositeColor, oppositePlayerPossibleMoves); int stability = (this.GetStableDiscsCount(board, color) - this.GetStableDiscsCount(board, oppositeColor)) * board.Size * 2 / 3; return(mobility + stability); } }
//функция оценки доски private int EvaluateBoard(Board board) { DiscColor color = this.Player.Color; DiscColor oppositeColor = DiscColor.GetOpposite(this.Player.Color); //списки предположительных ходов игроков List <int[]> oppositePlayerPossibleMoves = this.GetPossibleMoves(board, oppositeColor); List <int[]> possibleMoves = this.GetPossibleMoves(board, color); if ((possibleMoves.Count == 0) && (oppositePlayerPossibleMoves.Count == 0)) //если списки пусты { int result = board.GetDiscsCount(color) - board.GetDiscsCount(oppositeColor); //от количества фишек ии отнимает количество фишек противника int addend = (int)Math.Pow(board.Size, 4) + (int)Math.Pow(board.Size, 3); // потому что это конечное состояние, его вес должен быть больше эвристического if (result < 0) //если разность меньше 0 { addend = -addend; } return(result + addend); } else//если ходы есть { //количество фишек противника, которые могут быть преобразованы int mobility = this.GetPossibleConvertions(board, color, possibleMoves) - this.GetPossibleConvertions(board, oppositeColor, oppositePlayerPossibleMoves); //число стабильных фишек на доске игрока int stability = (this.GetStableDiscsCount(board, color) - this.GetStableDiscsCount(board, oppositeColor)) * board.Size * 2 / 3; return(mobility + stability); } }
private void InvertDirection( int rowIndex, int columnIndex, int rowIndexChange, int columnIndexChange, DiscColor color, ref int invertedDiscsCount) { DiscColor opositeColor = DiscColor.GetOpposite(color); rowIndex += rowIndexChange; columnIndex += columnIndexChange; while (this[rowIndex, columnIndex] == opositeColor) { this.mFieldColors[rowIndex, columnIndex] = color; invertedDiscsCount++; rowIndex += rowIndexChange; columnIndex += columnIndexChange; } }
// kiem tra xem co danh dc khong private bool CheckDirection(int rowIndex, int columnIndex, int rowIndexChange, int columnIndexChange, DiscColor color) { bool areOpositeColorDiscsFound = false; rowIndex += rowIndexChange; columnIndex += columnIndexChange; while ((rowIndex >= 0) && (rowIndex < this.Size) && (columnIndex >= 0) && (columnIndex < this.Size)) { if (areOpositeColorDiscsFound) { if (this[rowIndex, columnIndex] == color) { return(true); } else if (this[rowIndex, columnIndex] == DiscColor.None) { return(false); } } else { DiscColor opositeColor = DiscColor.GetOpposite(color); if (this[rowIndex, columnIndex] == opositeColor) { areOpositeColorDiscsFound = true; } else { return(false); } } rowIndex += rowIndexChange; columnIndex += columnIndexChange; } return(false); }
//проверка направлени¤ private bool CheckDirection(int rowIndex, int columnIndex, int rowIndexChange, int columnIndexChange, DiscColor color) { bool areOpositeColorDiscsFound = false;//поверка найден ли противоположный цвет rowIndex += rowIndexChange; columnIndex += columnIndexChange; while ((rowIndex >= 0) && (rowIndex < this.Size) && (columnIndex >= 0) && (columnIndex < this.Size)) { if (areOpositeColorDiscsFound)//если найдена клетка с противоположным цветом { if (this[rowIndex, columnIndex] == color) { return true; } else if (this[rowIndex, columnIndex] == DiscColor.None) { return false; } } else { DiscColor opositeColor = DiscColor.GetOpposite(color); if (this[rowIndex, columnIndex] == opositeColor) { areOpositeColorDiscsFound = true; } else { return false; } } rowIndex += rowIndexChange; columnIndex += columnIndexChange; } return false; }
private int GetNextMove(Board board, bool isMaximizing, int currentDepth, int alpha, int beta, out int resultRowIndex, out int resultColumnIndex) { resultRowIndex = 0; resultColumnIndex = 0; DiscColor color = isMaximizing ? this.Player.Color : DiscColor.GetOpposite(this.Player.Color); bool playerSkipsMove = false; List <int[]> possibleMoves = new List <int[]>(); bool isFinalMove = (currentDepth >= this.MaxDepth) || this.Player.Game.IsStopped || this.Player.Game.IsPaused; if (!isFinalMove) { possibleMoves = this.GetPossibleMoves(board, color); if (possibleMoves.Count == 0) { playerSkipsMove = true; possibleMoves = this.GetPossibleMoves(board, DiscColor.GetOpposite(color)); } isFinalMove = (possibleMoves.Count == 0); } if (isFinalMove) { resultRowIndex = -1; resultColumnIndex = -1; return(this.EvaluateBoard(board)); } else { int bestBoardValue = isMaximizing ? MIN_BOARD_VALUE : MAX_BOARD_VALUE; int bestMoveRowIndex = -1; int bestMoveColumnIndex = -1; foreach (int[] nextMove in possibleMoves) { int rowIndex = nextMove[0]; int columnIndex = nextMove[1]; Board nextBoard = (Board)board.Clone(); nextBoard.SetFieldColor(rowIndex, columnIndex, color); bool nextIsMaximizing = playerSkipsMove ? isMaximizing : !isMaximizing; int dummyIndex; // values of resultRowIndex and resultColumnIndex are not needed in recursive function calls int currentBoardValue = this.GetNextMove(nextBoard, nextIsMaximizing, currentDepth + 1, alpha, beta, out dummyIndex, out dummyIndex); if (isMaximizing) { if (currentBoardValue > bestBoardValue) { bestBoardValue = currentBoardValue; bestMoveRowIndex = rowIndex; bestMoveColumnIndex = columnIndex; if (bestBoardValue > alpha) { alpha = bestBoardValue; } if (bestBoardValue >= beta) { break; } } } else { if (currentBoardValue < bestBoardValue) { bestBoardValue = currentBoardValue; bestMoveRowIndex = rowIndex; bestMoveColumnIndex = columnIndex; if (bestBoardValue < beta) { beta = bestBoardValue; } if (bestBoardValue <= alpha) { break; } } } } resultRowIndex = bestMoveRowIndex; resultColumnIndex = bestMoveColumnIndex; return(bestBoardValue); } }
//процедура для осуществления следующего хода. алгоритм АВ-отсечения. ищет лучший ход. возвращает BestBoardValue в виде числа (вероятности) private int GetNextMove(Board board, bool isMaximizing, int currentDepth, int alpha, int beta, out int resultRowIndex, out int resultColumnIndex) { resultRowIndex = 0; resultColumnIndex = 0; //цвет фишки DiscColor color = isMaximizing ? this.Player.Color : DiscColor.GetOpposite(this.Player.Color);//если true DiskColor = Player.Color иначе противоположный цвет bool playerSkipsMove = false; List <int[]> possibleMoves = new List <int[]>(); //проверка на последний ход bool isFinalMove = (currentDepth >= this.MaxDepth) || this.Player.Game.IsStopped || this.Player.Game.IsPaused; //если ход не последний if (!isFinalMove) { //получение возможных ходов. possibleMoves = this.GetPossibleMoves(board, color); if (possibleMoves.Count == 0) //если нет возможных ходов { playerSkipsMove = true; possibleMoves = this.GetPossibleMoves(board, DiscColor.GetOpposite(color));//получить список возможных ходов для противоположного игрока } isFinalMove = (possibleMoves.Count == 0); //проверка на последний ход (если список пуст вернет true) } //если используем на самом "дне" глубины подсчета if (isFinalMove) { resultRowIndex = -1; resultColumnIndex = -1; return(this.EvaluateBoard(board));//возвращает оценочную эвристическую функцию (mobility+stability) } else//если макс. глубине не достигнута { //поиск наилучшего хода (просмотр дерева) int bestBoardValue = isMaximizing ? MIN_BOARD_VALUE : MAX_BOARD_VALUE; //в начале bestBoardValue присваивается + или - бесконечность int bestMoveRowIndex = -1; //инициализация координат лучшего хода int bestMoveColumnIndex = -1; foreach (int[] nextMove in possibleMoves) { int rowIndex = nextMove[0]; int columnIndex = nextMove[1]; Board nextBoard = (Board)board.Clone(); //копия доски nextBoard.SetFieldColor(rowIndex, columnIndex, color); //установка фишек на доску bool nextIsMaximizing = playerSkipsMove ? isMaximizing : !isMaximizing; int dummyIndex; // значения resultRowIndex и resultColumnIndex не нуждаются в рекурсивном вызове функции //рекурсивный вызов int currentBoardValue = this.GetNextMove(nextBoard, nextIsMaximizing, currentDepth + 1, alpha, beta, out dummyIndex, out dummyIndex); if (isMaximizing) { if (currentBoardValue > bestBoardValue) { bestBoardValue = currentBoardValue; bestMoveRowIndex = rowIndex; bestMoveColumnIndex = columnIndex; //Найти оценку текущей ситуации, в предположении, что она находится между alpha и beta. if (bestBoardValue > alpha) { alpha = bestBoardValue; } if (bestBoardValue >= beta) { break; } } } else { if (currentBoardValue < bestBoardValue) { bestBoardValue = currentBoardValue; bestMoveRowIndex = rowIndex; bestMoveColumnIndex = columnIndex; if (bestBoardValue < beta) { beta = bestBoardValue; } if (bestBoardValue <= alpha) { break; } } } } resultRowIndex = bestMoveRowIndex; resultColumnIndex = bestMoveColumnIndex; return(bestBoardValue); } }