public ErrorCondition Move(AnnotatedMove move) => Move(move.Move);
// Parses a move, but does not determine validity public static bool TryParseMove(string input, BoardState state, ulong piecesOnCurrentSide, out AnnotatedMove result) { // ✔ Account for castling (O-O, O-O-O) // ✔ Account for regular move (a4, Ng8) // ✔ Account for long-form move (Nb1 c3, Nb1-c3) // ✔ Account for long-form capture (Ne2xa4) // ✔ Account for short-form capture (Nxg4, axb4) // ✔ Account for disambiguation (Ngg4) // ✔ Account for piece promotions (e8=Q) // ✔ Account for promoted piece must be own colour // ✔ Account for if pawn moves to end without specifying promotion // ✔ Account for if non-pawn specifies promotion // ✔ Account for if promotion piece tries to become pawn // ✔ Account for if specify promotion when not at end // ✔ Account for state change marks (Na4+, e2#) // ✔ Account for annotations (Na4!, e2??, b5!?) // ✔ Account for whitespace (Ne2 x a4) - fail in this case // ✔ Account for invalid ranks/files - fail in this case var trimmedInput = input.AsSpan().Trim(); if (trimmedInput.IsEmpty || trimmedInput.IndexOf(' ') != -1) { result = AnnotatedMove.Empty; return(false); } var isWhiteMove = piecesOnCurrentSide == state.WhitePieces; var moveNotation = TrimMoveDescriptors(trimmedInput); if (moveNotation.IsEmpty) { result = AnnotatedMove.Empty; return(false); } var moveDescriptors = moveNotation.Length == trimmedInput.Length ? ReadOnlySpan <char> .Empty : trimmedInput.Slice(moveNotation.Length); var promotion = GetPromotion(moveDescriptors, isWhiteMove); if (promotion != SquareContents.Empty) { moveDescriptors = moveDescriptors.Length > 2 ? moveDescriptors.Slice(2) : ReadOnlySpan <char> .Empty; } var annotation = GetAnnotation(moveDescriptors); var attackState = GetAttackState(moveDescriptors); // Handle castling if (TryHandleCastling(moveNotation, isWhiteMove, out var move)) { result = new AnnotatedMove(move, annotation, attackState); return(true); } // Read leading piece designation char pieceDesignation; if (PieceDesignations.Contains(moveNotation[0])) { pieceDesignation = moveNotation[0]; moveNotation = moveNotation.Slice(1); } else { pieceDesignation = Constants.PieceNotation.Pawn; } int squareIdx = moveNotation.Length - 1; // Get end square (must be present) var parsedState = new ParsedMoveState(); parsedState.EndRank = moveNotation[squareIdx--] - '0'; parsedState.EndFile = Char.ToLower(moveNotation[squareIdx--]); var lastRankForColor = isWhiteMove ? Constants.Board.NumberOfRows : 1; if (promotion != 0) { if ( pieceDesignation != Constants.PieceNotation.Pawn || // promoted non-pawn (promotion & SquareContents.Pawn) != 0 || // promoted to invalid piece (pawn) parsedState.EndRank != lastRankForColor // promoted but not at end ) { result = AnnotatedMove.Empty; return(false); } parsedState.PromotedPiece = promotion; } else if (pieceDesignation == Constants.PieceNotation.Pawn && parsedState.EndRank == lastRankForColor) { // Moved pawn to end without promoting result = AnnotatedMove.Empty; return(false); } // Ignore delimiter (if present) bool isCapture = false; if (squareIdx >= 0 && SquareDelimiters.Contains(moveNotation[squareIdx])) { isCapture = moveNotation[squareIdx] == Constants.MoveType.Capture; squareIdx--; } // Read start squares (if present) if (squareIdx >= 0 && Char.IsDigit(moveNotation[squareIdx])) { parsedState.StartRank = moveNotation[squareIdx--] - '0'; } if (squareIdx >= 0 && Char.IsLetter(moveNotation[squareIdx])) { parsedState.StartFile = Char.ToLower(moveNotation[squareIdx--]); } if (parsedState.StartRank != 0 && parsedState.StartFile != 0) { var valid = IsMoveValid(parsedState); result = valid ? new AnnotatedMove(parsedState.ToMove(), annotation, attackState) : AnnotatedMove.Empty; return(valid); } if (TryInferStartSquare(state, piecesOnCurrentSide, isWhiteMove, isCapture, pieceDesignation, ref parsedState)) { var valid = IsMoveValid(parsedState); result = valid ? new AnnotatedMove(parsedState.ToMove(), annotation, attackState) : AnnotatedMove.Empty; return(valid); } result = AnnotatedMove.Empty; return(false); }
public static bool Equals(AnnotatedMove a, AnnotatedMove b) { return(a.Annotation == b.Annotation && a.AttackState == b.AttackState && a == b); }