/// <summary> /// Выбрать ход с лучшей оценкой из списка. /// </summary> /// <param name="boardState">Состояние доски.</param> /// <param name="moves">Список ходов.</param> private static FigureMove GetBestMove(BoardState boardState, List <FigureMove> moves) { FigureMove bestMove = null; double bestValue = EvaluateBoard(boardState); foreach (FigureMove move in moves) { // Создаем виртуальную доску BoardState virtualBoard = new BoardState(boardState); // Двигаем фигуру virtualBoard.ExecuteMove(move); // Оцениваем ход double boardValue = EvaluateBoard(virtualBoard); if (boardState.turnColor == Figure.FigureColor.white && boardValue > bestValue) { bestMove = move; bestValue = boardValue; } if (boardState.turnColor == Figure.FigureColor.black && boardValue < bestValue) { bestMove = move; bestValue = boardValue; } } // Если нет хода улучшающего оценку доски, берем случайный ход if (bestMove is null) { return(RandomMove(boardState)); } return(bestMove); }
/// <summary> /// Возвращает ход с лучшей оценкой. /// </summary> private static FigureMove BestEvaluationMove(BoardState boardState) { // Ищем ход с лучшей оценкой List <FigureMove> availableMoves = boardState.GetLegalMoves(); FigureMove bestMove = null; double bestValue = EvaluateBoard(boardState); foreach (FigureMove move in availableMoves) { double boardValueAfterMove = EvaluateBoard(move.boardStateAfterMove); if (boardState.turnColor == Figure.FigureColor.white && boardValueAfterMove > bestValue) { bestMove = move; bestValue = boardValueAfterMove; } if (boardState.turnColor == Figure.FigureColor.black && boardValueAfterMove < bestValue) { bestMove = move; bestValue = boardValueAfterMove; } } // Если нет хода улучшающего оценку доски, берем случайный ход if (bestMove is null) { return(RandomMove(boardState)); } return(bestMove); }
/// <summary> /// Делает случайный ход. /// </summary> private static FigureMove RandomMove(BoardState boardState) { List <FigureMove> availableMoves = boardState.moveList.FindAll(move => move.attackingFigures.Count == 0); FigureMove randomMove = availableMoves[random.Next(availableMoves.Count)]; return(randomMove); }
/// <summary> /// Возвращает ход с лучшей оценкой с помощью алгоритма минимакс. /// </summary> private static FigureMove Minimax(BoardState boardState, int maxDepth) { // Список разрешенных ходов List <FigureMove> availableMoves = boardState.GetLegalMoves(); // Оценки ходов moveCheckedCounter = 0; List <double> moveValues = availableMoves.Select(move => Alphabeta(move, 0, maxDepth, double.PositiveInfinity, double.NegativeInfinity)).ToList(); UnityEngine.Debug.Log($"{moveCheckedCounter} moves checked"); // Значение лучшей оценки double bestMoveValue = boardState.turnColor == Figure.FigureColor.white ? moveValues.Max() : moveValues.Min(); // Выбираем ходы с лучшей оценкой List <FigureMove> movesWithBestvalue = new List <FigureMove>(); for (int i = 0; i < moveValues.Count; i++) { if (moveValues[i] == bestMoveValue) { movesWithBestvalue.Add(availableMoves[i]); } } // Выбираем случайный ход из ходов с лучшей оценкой FigureMove bestMove = movesWithBestvalue[random.Next(movesWithBestvalue.Count)]; return(bestMove); }
/// <summary> /// Возвращает список ходов, доступных после этого хода /// </summary> public List <FigureMove> GetDerivedMoves(FigureMove move) { BoardState virtualBoard = move.boardStateAfterMove; virtualBoard.UpdateLegalMoves(); List <FigureMove> derivedMoves = virtualBoard.GetLegalMoves(); return(derivedMoves); }
private void FixedUpdate() { // Выполняем ход ИИ if (currentAiMove != null) { BeginMove(currentAiMove); currentAiMove = null; } }
/// <summary> /// Совершить ход. /// </summary> public void ExecuteMove(FigureMove move) { Figure figure = GetFigureAtCell(move.from); if (figure == null) { throw new InvalidOperationException("Невозможно совершить ход: не найдена фигура"); } figure.ExecuteMove(move); }
/// <summary> /// Поток ИИ. /// </summary> public void AiThreadFunc() { while (true) { if (boardState.turnColor == Figure.FigureColor.black && !interfaceLocked) { currentAiMove = AiModule.AiMove(boardState); } Thread.Sleep(100); } }
private bool ValidateFigureMove(FigureMove move, PlayerType playerType) { var sourceCoordinate = playerType == PlayerType.BottomPlayer ? bottomPlayerPosition : topPlayerPosition; var targetCoordinate = move.NewPosition; var sourceNode = GetNode(sourceCoordinate); var targetNode = GetNode(targetCoordinate); return(sourceNode.Neighbours.Contains(targetNode)); }
/// <summary> /// Запуск анимации перемещения фигуры. Ход фигуры на BoardState выполняется после завершения анимации. /// </summary> /// <param name="move"></param> public void BeginMove(FigureMove move) { // Блокируем интерфейс interfaceLocked = true; // Убираем выделение PieceController.ClearSelection(); // Убираем все красные линии foreach (GameObject redLine in redLines) { Destroy(redLine); } redLines.Clear(); // Находим GameObject фигуры Transform piece = FindTransformByPos(move.from); // Перемещаем спрайт на слой выше SpriteRenderer spriteRenderer = piece.GetChild(0).GetComponent <SpriteRenderer>(); spriteRenderer.sortingLayerName = "CurrentPiece"; currentMovingPiece = piece; // Запускаем анимацию MoveAnimation moveAnimation = piece.GetComponent <MoveAnimation>(); currentMove = move; moveAnimation.StartAnimation( beginPos: new Vector3(move.from.x, move.from.y), endPos: new Vector3(move.to.x, move.to.y), finishedCallback: EndMove ); // При рокировке запускаем анимацию для ладьи if (move.GetType() == typeof(CastlingMove)) { // Находим GameObject ладьи CastlingMove castlingMove = (CastlingMove)move; Transform rook = FindTransformByPos(castlingMove.rookFrom); // Запускаем анимацию MoveAnimation rookMoveAnimation = rook.GetComponent <MoveAnimation>(); rookMoveAnimation.StartAnimation( beginPos: new Vector3(castlingMove.rookFrom.x, castlingMove.rookFrom.y), endPos: new Vector3(castlingMove.rookTo.x, castlingMove.rookTo.y), finishedCallback: null ); } }
/// <summary> /// Двигает короля в другую клетку. /// </summary> public override void ExecuteMove(FigureMove move) { if (move.GetType() == typeof(CastlingMove)) { CastlingMove castlingMove = (CastlingMove)move; // Ищем ладью Figure rook = boardState.GetFigureAtCell(castlingMove.rookFrom); if (rook == null || rook.GetType() != typeof(Rook)) { throw new InvalidOperationException("Не найдена ладья для рокировки"); } // Двигаем ладью MoveFigure(rook, castlingMove.rookTo, takeFigure: false); } // Вызов базового метода Move base.ExecuteMove(move); }
/// <summary> /// Рекурсивная часть функции Minimax. /// </summary> private static double Alphabeta(FigureMove move, int currentDepth, int maxDepth, double alpha, double beta) { moveCheckedCounter++; // Если достигли конца дерева, получаем оценку доски if (currentDepth >= maxDepth) { return(EvaluateBoard(move.boardStateAfterMove)); } // Обновляем список ходов move.boardStateAfterMove.UpdateLegalMoves(); // Получаем оценку каждого хода List <FigureMove> moves = move.boardStateAfterMove.GetLegalMoves(); if (move.color == Figure.FigureColor.white) { double value = double.NegativeInfinity; foreach (FigureMove nextMove in moves) { value = Math.Max(value, Alphabeta(nextMove, currentDepth + 1, maxDepth, alpha, beta)); alpha = Math.Max(alpha, value); if (alpha >= beta) { break; } } return(value); } else { double value = double.PositiveInfinity; foreach (FigureMove nextMove in moves) { value = Math.Min(value, Alphabeta(nextMove, currentDepth + 1, maxDepth, alpha, beta)); beta = Math.Min(beta, value); if (beta <= alpha) { break; } } return(value); } }
/// <summary> /// Двигает пешку в другую клетку. /// </summary> public override void ExecuteMove(FigureMove move) { // Взятие на проходе bool longDistanceY = Math.Abs(move.to.y - y) > 1; if (longDistanceY) { int direction = color == FigureColor.white ? 1 : -1; Figure left = boardState.GetFigureAtCell(Pos + new Vector2Int(-1, direction)); Figure right = boardState.GetFigureAtCell(Pos + new Vector2Int(1, direction)); if (left != null && left.GetType() == typeof(Pawn) && left.color == InvertColor(color)) { left.Delete(); } if (right != null && right.GetType() == typeof(Pawn) && right.color == InvertColor(color)) { right.Delete(); } } // Вызов базового метода ExecuteMove base.ExecuteMove(move); // Превращение в ферзя bool whitePawn = (color == FigureColor.white) && (move.to.y == 7); bool blackPawn = (color == FigureColor.black) && (move.to.y == 0); if (whitePawn || blackPawn) { // Удаляем пешку Delete(); // Создаем ферзя Queen queen = new Queen(move.to.x, move.to.y, color, boardState); boardState.figures.Add(queen); boardState.figureCreatedCallback?.Invoke(queen); } }
public bool IsPawnCorrect_Test(string start, string end) { return(FigureMove.IsPawnCorrect(start, end)); }
protected override void NeedToAwake() { figureData = GetComponent<FigureData>(); if(gameObject.GetComponents<FigureMove>() != null) figureMove = GetComponent<FigureMove>(); if(gameObject.GetComponent<PlayerJump>() != null) playerJump = GetComponent<PlayerJump>(); SecNeedToAwake (); }