protected override Player CalculateWinner()
        {
            var winner = Player.None;

            var currentPlayer      = IsPlayerTurn(Player.First) ? Player.First : Player.Second;
            var currentPlayerMoves = GetValidMoves(currentPlayer);

            if (currentPlayerMoves.Any(move => move.WouldCaptureKing))
            {
                // The opponent has their king in check and cannot move because
                // it is not their turn anymore, so they have lost the match
                winner = currentPlayer;
            }
            else
            {
                var opponentPlayer      = currentPlayer.ToOppositePlayer();
                var opponentPlayerMoves = GetValidMoves(opponentPlayer);
                var kingIsInCheck       = opponentPlayerMoves.Any(move => move.WouldCaptureKing);
                if (kingIsInCheck)
                {
                    winner = opponentPlayer;

                    // Current player is in check, we have to see whether they can avoid the checkmate
                    var shouldBreakLoop = false;
                    foreach (var currentPlayerMove in currentPlayerMoves)
                    {
                        MovesEngine.TryMakeDummyMove <ChessBoard, ChessMoveInfo, ChessBoardState>(this, currentPlayerMove, tempBoard =>
                        {
                            var newOpponentPlayerMoves = tempBoard.GetValidMoves(opponentPlayer);
                            var kingRemainsInCheck     = newOpponentPlayerMoves.Any(move => move.WouldCaptureKing);
                            if (!kingRemainsInCheck)
                            {
                                // The player is able to avoid the check thanks to this move
                                winner          = Player.None;
                                shouldBreakLoop = true;
                            }
                        }, shouldBeValid: false);

                        if (shouldBreakLoop)
                        {
                            break;
                        }
                    }
                }
            }

            return(winner);
        }
        private List <ChessMoveInfo> FilterOutInvalidKingMoves(Player player, List <ChessMoveInfo> uncheckedKingMoves, int forwardMotion)
        {
            var validKingMoves = new List <ChessMoveInfo>();

            if (!uncheckedKingMoves.Any())
            {
                return(validKingMoves);
            }

            var opponent      = player.ToOppositePlayer();
            var opponentMoves = CalculateValidMoves(opponent, filterOutInvalidKingMoves: false);

            foreach (var potentialKingMove in uncheckedKingMoves)
            {
                if (!potentialKingMove.IsCastling)
                {
                    var pieceToCapture = potentialKingMove.MoveSteps.First().PieceToCapture;
                    if (!pieceToCapture.IsNone())
                    {
                        // If the king would capture a piece with his move, then we cannot use the current valid moves of the opponent to verify
                        // this king move, as said valid moves would be altered after the piece is captured. Hence, we need to pretend to make
                        // the move and then recalculate the opponent's moves in order to verify whether the king would be in check or not.
                        MovesEngine.TryMakeDummyMove <ChessBoard, ChessMoveInfo, ChessBoardState>(this, potentialKingMove, tempBoard =>
                        {
                            var opponentMovesAfterKingMove = tempBoard.CalculateValidMoves(opponent, filterOutInvalidKingMoves: false);
                            var kingIsInCheckAfterMove     = opponentMovesAfterKingMove.Any(move => move.WouldCaptureKing);
                            if (!kingIsInCheckAfterMove)
                            {
                                validKingMoves.Add(potentialKingMove);
                            }
                        }, shouldBeValid: false);
                    }
                    else
                    {
                        var kingMoveDestination = potentialKingMove.MoveSteps.First().NewPosition;
                        if (!opponentMoves.Any(move => move.MoveSteps.First().PieceToMove.Type != PieceType.Pawn && move.MoveSteps.First().NewPosition.Equals(kingMoveDestination)))
                        {
                            // There is no move that would cause the opponent's piece to land on this new position of the king,
                            // so it is likely that this king move won't result on a check. However, we still have to look for
                            // pawns, as they move differently to capture pieces than they do to advance.
                            var upLeftPosition = new PiecePosition(kingMoveDestination.HorizontalPosition + forwardMotion, kingMoveDestination.VerticalPosition + forwardMotion);
                            var upLeftPiece    = upLeftPosition.IsValid() ? GetPiece(upLeftPosition) : null;
                            if (!upLeftPiece.IsNone() && upLeftPiece.Type == PieceType.Pawn && upLeftPiece.Player == opponent)
                            {
                                // After this potential king move, the piece in front of the king and to his left would be an opponent's pawn,
                                // so this move isn't allowed for the king because it would result in a check
                                continue;
                            }

                            var upRightPosition = new PiecePosition(kingMoveDestination.HorizontalPosition - forwardMotion, kingMoveDestination.VerticalPosition + forwardMotion);
                            var upRightPiece    = upRightPosition.IsValid() ? GetPiece(upRightPosition) : null;
                            if (!upRightPiece.IsNone() && upRightPiece.Type == PieceType.Pawn && upRightPiece.Player == opponent)
                            {
                                // After this potential king move, the piece in front of the king and to his right would be an opponent's pawn,
                                // so this move isn't allowed for the king because it would result in a check
                                continue;
                            }

                            validKingMoves.Add(potentialKingMove);
                        }
                    }
                }
                else
                {
                    // The castling move can only be made if the king is not currently in check
                    var kingIsInCheck = opponentMoves.Any(move => move.WouldCaptureKing);
                    if (!kingIsInCheck)
                    {
                        validKingMoves.Add(potentialKingMove);
                    }
                }
            }

            return(validKingMoves);
        }