Example #1
0
    /// <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);
    }
Example #2
0
    /// <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);
    }
Example #3
0
    /// <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);
    }
Example #4
0
    /// <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);
    }
Example #5
0
    /// <summary>
    /// Возвращает список ходов, доступных после этого хода
    /// </summary>
    public List <FigureMove> GetDerivedMoves(FigureMove move)
    {
        BoardState virtualBoard = move.boardStateAfterMove;

        virtualBoard.UpdateLegalMoves();
        List <FigureMove> derivedMoves = virtualBoard.GetLegalMoves();

        return(derivedMoves);
    }
Example #6
0
 private void FixedUpdate()
 {
     // Выполняем ход ИИ
     if (currentAiMove != null)
     {
         BeginMove(currentAiMove);
         currentAiMove = null;
     }
 }
Example #7
0
    /// <summary>
    /// Совершить ход.
    /// </summary>
    public void ExecuteMove(FigureMove move)
    {
        Figure figure = GetFigureAtCell(move.from);

        if (figure == null)
        {
            throw new InvalidOperationException("Невозможно совершить ход: не найдена фигура");
        }
        figure.ExecuteMove(move);
    }
Example #8
0
 /// <summary>
 /// Поток ИИ.
 /// </summary>
 public void AiThreadFunc()
 {
     while (true)
     {
         if (boardState.turnColor == Figure.FigureColor.black && !interfaceLocked)
         {
             currentAiMove = AiModule.AiMove(boardState);
         }
         Thread.Sleep(100);
     }
 }
Example #9
0
        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));
        }
Example #10
0
    /// <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
                );
        }
    }
Example #11
0
 /// <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);
 }
Example #12
0
    /// <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);
        }
    }
Example #13
0
    /// <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);
        }
    }
Example #14
0
 public bool IsPawnCorrect_Test(string start, string end)
 {
     return(FigureMove.IsPawnCorrect(start, end));
 }
Example #15
0
    protected override void NeedToAwake()
    {
        figureData = GetComponent<FigureData>();

        if(gameObject.GetComponents<FigureMove>() != null)
            figureMove = GetComponent<FigureMove>();

        if(gameObject.GetComponent<PlayerJump>() != null)
            playerJump = GetComponent<PlayerJump>();
        SecNeedToAwake ();
    }