src/Engine/ChessEngine.cs
/// <summary>
/// Gets a move from the algebraic representation of the move. Uses the current game state to resolve ambiguity (like which piece was moved).
/// </summary>
/// <param name="move">A string representing a move in algebraic notation.</param>
/// <returns>The move indicated by the input string.</returns>
Gets a move from the algebraic representation of the move. Uses the current game state to resolve ambiguity (like which piece was moved).
Gets a move from the algebraic representation of the move . Uses the current game state to resolve ambiguity ( like which piece was moved ) .
public Move MoveFromAlgebraicNotation(string move)
        {
            if (move is null)
            {
                throw new ArgumentNullException(nameof(move));
            }
            var match = AlgebraicNotationRegex.Match(move);
            if (!match.Success)
            {
                throw new ArgumentException("Move is not valid algebraic notation", nameof(move));
            }
            ChessPieces? pieceMoved = null;
            ChessPieces? promotedTo = null;
            int? originalRank = null;
            int? originalFile = null;
            BoardPosition finalPosition = default;
            if (match.Groups["longCastle"].Success)
            {
                (pieceMoved, finalPosition) = Game.WhiteToMove
                    ? (ChessPieces.WhiteKing, new BoardPosition(2, 0))
                    : (ChessPieces.BlackKing, new BoardPosition(2, 7));
            }
            else if (match.Groups["shortCastle"].Success)
            {
                (pieceMoved, finalPosition) = Game.WhiteToMove
                    ? (ChessPieces.WhiteKing, new BoardPosition(6, 0))
                    : (ChessPieces.BlackKing, new BoardPosition(6, 7));
            }
            else
            {
                finalPosition = new BoardPosition(match.Groups["finalPosition"].Value);
                if (match.Groups["originalFile"].Success)
                {
                    originalFile = ChessFormatter.FileFromString(match.Groups["originalFile"].Value);
                }
                if (match.Groups["originalRank"].Success)
                {
                    originalRank = ChessFormatter.RankFromString(match.Groups["originalRank"].Value);
                }
                if (match.Groups["promotedTo"].Success)
                {
                    var promotedToString = match.Groups["promotedTo"].Value;
                    if (!Game.WhiteToMove)
                    {
                        promotedToString = promotedToString.ToLowerInvariant();
                    }
                    promotedTo = ChessFormatter.PieceFromString(promotedToString);
                }
                var pieceMatch = match.Groups["piece"];
                if (pieceMatch.Success)
                {
                    var pieceString = match.Groups["piece"].Value;
                    if (!Game.WhiteToMove)
                    {
                        pieceString = pieceString.ToLowerInvariant();
                    }
                    pieceMoved = ChessFormatter.PieceFromString(pieceString);
                }
                else if (originalRank.HasValue && originalFile.HasValue)
                {
                    var originalPosition = new BoardPosition(originalFile.Value, originalRank.Value);
                    pieceMoved = Game.GetPiece(originalPosition)?.PieceType
                        ?? throw new ArgumentException($"Cannot make move {move} from {originalPosition}; there is no piece there.", nameof(move));
                }
                else
                {
                    pieceMoved = Game.WhiteToMove ? ChessPieces.WhitePawn : ChessPieces.BlackPawn;
                }
            }
            var possiblePieces = Game.Pieces.Where(p => p.PieceType == pieceMoved);
            if (originalFile.HasValue)
            {
                possiblePieces = possiblePieces.Where(p => p.Position.File == originalFile);
            }
            if (originalRank.HasValue)
            {
                possiblePieces = possiblePieces.Where(p => p.Position.Rank == originalRank);
            }
            var possibleMoves = possiblePieces.SelectMany(p => GetLegalMoves(p.Position))
                .Where(m => m.FinalPosition == finalPosition);
            if (possibleMoves.Count() > 1)
            {
                throw new ArgumentException($"The move {move} is ambiguous", nameof(move));
            }
            if (possibleMoves.Count() == 0)
            {
                throw new ArgumentException($"The move {move} is impossible", nameof(move));
            }
            var resolvedMove = possibleMoves.First();
            if (promotedTo.HasValue)
            {
                resolvedMove.PiecePromotedTo = promotedTo;
            }
            return resolvedMove;
        }
public Move MoveFromAlgebraicNotation ( string move ) { if ( move is null ) { throw new ArgumentNullException ( nameof ( move ) ) ; } var match = AlgebraicNotationRegex . Match ( move ) ; if ( ! match . Success ) { throw new ArgumentException ( " " , nameof ( move ) ) ; } ChessPieces ? pieceMoved = null ; ChessPieces ? promotedTo = null ; int ? originalRank = null ; int ? originalFile = null ; BoardPosition finalPosition = default ; if ( match . Groups [ " " ] . Success ) { ( pieceMoved , finalPosition ) = Game . WhiteToMove ? ( ChessPieces . WhiteKing , new BoardPosition ( 2 , 0 ) ) : ( ChessPieces . BlackKing , new BoardPosition ( 2 , 7 ) ) ; } else if ( match . Groups [ " " ] . Success ) { ( pieceMoved , finalPosition ) = Game . WhiteToMove ? ( ChessPieces . WhiteKing , new BoardPosition ( 6 , 0 ) ) : ( ChessPieces . BlackKing , new BoardPosition ( 6 , 7 ) ) ; } else { finalPosition = new BoardPosition ( match . Groups [ " " ] . Value ) ; if ( match . Groups [ " " ] . Success ) { originalFile = ChessFormatter . FileFromString ( match . Groups [ " " ] . Value ) ; } if ( match . Groups [ " " ] . Success ) { originalRank = ChessFormatter . RankFromString ( match . Groups [ " " ] . Value ) ; } if ( match . Groups [ " " ] . Success ) { var promotedToString = match . Groups [ " " ] . Value ; if ( ! Game . WhiteToMove ) { promotedToString = promotedToString . ToLowerInvariant ( ) ; } promotedTo = ChessFormatter . PieceFromString ( promotedToString ) ; } var pieceMatch = match . Groups [ " " ] ; if ( pieceMatch . Success ) { var pieceString = match . Groups [ " " ] . Value ; if ( ! Game . WhiteToMove ) { pieceString = pieceString . ToLowerInvariant ( ) ; } pieceMoved = ChessFormatter . PieceFromString ( pieceString ) ; } else if ( originalRank . HasValue && originalFile . HasValue ) { var originalPosition = new BoardPosition ( originalFile . Value , originalRank . Value ) ; pieceMoved = Game . GetPiece ( originalPosition ) ? . PieceType ?? throw new ArgumentException ( $" Cannot make move  { move }  from  { originalPosition } ; there is no piece there. " , nameof ( move ) ) ; } else { pieceMoved = Game . WhiteToMove ? ChessPieces . WhitePawn : ChessPieces . BlackPawn ; } } var possiblePieces = Game . Pieces . Where ( p => p . PieceType == pieceMoved ) ; if ( originalFile . HasValue ) { possiblePieces = possiblePieces . Where ( p => p . Position . File == originalFile ) ; } if ( originalRank . HasValue ) { possiblePieces = possiblePieces . Where ( p => p . Position . Rank == originalRank ) ; } var possibleMoves = possiblePieces . SelectMany ( p => GetLegalMoves ( p . Position ) ) . Where ( m => m . FinalPosition == finalPosition ) ; if ( possibleMoves . Count ( ) > 1 ) { throw new ArgumentException ( $" The move  { move }  is ambiguous " , nameof ( move ) ) ; } if ( possibleMoves . Count ( ) == 0 ) { throw new ArgumentException ( $" The move  { move }  is impossible " , nameof ( move ) ) ; } var resolvedMove = possibleMoves . First ( ) ; if ( promotedTo . HasValue ) { resolvedMove . PiecePromotedTo = promotedTo ; } return resolvedMove ; }
Gets a move from the algebraic representation of the move.
Gets a move from the algebraic representation of the move .
// These locals will store what we know about the move from the parsed string // and will be used to look up the move from legal possibilities. // Check for castling // If not castling, identify piece type, disambiguators, final position, and promotion // Note the original file if specified // Note the original rank if specified // Note the piece promoted to if specified // If the piece type was specified, use that to identify piece moved. // If black is to move next, make the piece string lower case so that it // is interpretted by the formatted as a black piece. // If the piece type isn't specified, look for original rank and file since some algebraic // notations include these but omit piece type. // Default to pawn // Identify possible pieces moved // Find move
The move indicated by the input string.
The move indicated by the input string .
move
string
A string representing a move in algebraic notation.
A string representing a move in algebraic notation .