private static Location InferSource( string partialSource, State ctx, Location destination, PieceKind sourceKind, bool isCapture) { Debug.Assert(partialSource.Length >= 0 && partialSource.Length <= 2); bool realIsCapture = ctx[destination].HasPiece || (sourceKind == PieceKind.Pawn && destination == ctx.EnPassantTarget); if (isCapture != realIsCapture) { throw new InvalidMoveException(InvalidMoveReason.BadCaptureNotation); } var possibleSources = ctx.ActivePlayer.GetOccupiedTiles(); char?fileChar = (partialSource.Length == 1 && partialSource[0] >= 'a' && partialSource[0] <= 'h') ? partialSource[0] : (char?)null; char?rankChar = (partialSource.Length == 1 && partialSource[0] >= '1' && partialSource[0] <= '8') ? partialSource[0] : (char?)null; if (partialSource.Length == 2) { var sourceLocation = Location.Parse(partialSource); possibleSources = new[] { ctx[sourceLocation] }; } else if (fileChar != null) { var sourceFile = FileHelpers.FromChar(fileChar.Value); possibleSources = possibleSources.Where(t => t.Location.File == sourceFile); } else if (rankChar != null) { var sourceRank = RankHelpers.FromChar(rankChar.Value); possibleSources = possibleSources.Where(t => t.Location.Rank == sourceRank); } try { var sourceTile = possibleSources.Single(t => t.Piece.Kind == sourceKind // Castling should be denoted with the special notation O-O / O-O-O, we don't want to accept Kg1 / Kc1 && ctx.Inner.IsMovePseudoLegal(t.Location, destination, allowCastling: false)); return(sourceTile.Location); } catch (InvalidOperationException e) { throw new InvalidMoveException(InvalidMoveReason.CouldNotInferSource, e); } }
private Location?ReadLocation() { if (!CanRead(2)) { return(null); } var(fileChar, rankChar) = (Peek(), Peek(1)); if (fileChar < 'a' || fileChar > 'h') { return(null); } if (rankChar < '1' || rankChar > '8') { return(null); } return(FileHelpers.FromChar(Pop()), RankHelpers.FromChar(Pop())); }