Exemple #1
0
    /// <summary>
    /// Loads ChessBoard from Forsyth-Edwards Notation<br/>
    /// ex.:<br/>
    /// rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
    /// </summary>
    /// <param name="fen">FEN string to load</param>
    /// <returns>ChessBoard with according positions</returns>
    /// <exception cref="ChessArgumentException">Given FEN string didn't match the Regex pattern</exception>
    public static ChessBoard LoadFromFen(string fen)
    {
        var(succeeded, exception) = FenBoardBuilder.TryLoad(fen, out var builder);

        if (!succeeded && exception is not null)
        {
            throw exception;
        }

        return(BuildBoardFromFen(builder));
    }
Exemple #2
0
    /// <summary>
    /// Tries to load
    /// ChessBoard from Forsyth-Edwards Notation<br/>
    /// ex.:<br/>
    /// rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
    /// </summary>
    /// <param name="fen">FEN string to load</param>
    /// <param name="board">Result with loaded board</param>
    /// <returns>Whether load is succeeded</returns>
    public static bool TryLoadFromFen(string fen, [NotNullWhen(true)] out ChessBoard?board)
    {
        var(succeeded, _) = FenBoardBuilder.TryLoad(fen, out var builder);

        if (!succeeded)
        {
            board = null;
            return(false);
        }

        board = BuildBoardFromFen(builder);

        return(true);
    }
Exemple #3
0
    private static ChessBoard BuildBoardFromFen(FenBoardBuilder builder)
    {
        var board = new ChessBoard
        {
            FenBuilder = builder,
            pieces     = builder.Pieces
        };

        board.headers.Add("Variant", "From Position");
        board.headers.Add("FEN", builder.ToString());

        board.HandleKingChecked();
        board.HandleEndGame();

        return(board);
    }
Exemple #4
0
    internal static (bool succeeded, ChessException?exception) TryLoad(string fen, out FenBoardBuilder?builder)
    {
        builder = null;

        var matches = Regexes.regexFen.Matches(fen);

        if (matches.Count == 0)
        {
            return(false, new ChessArgumentException(null, "FEN board string should match pattern: " + Regexes.FenPattern));
        }

        builder = new FenBoardBuilder();

        foreach (var group in matches[0].Groups.Values)
        {
            switch (group.Name)
            {
            case "1":
                // Set pieces to given positions
                int x = 0, y = 7;
                for (int i = 0; i < group.Length; i++)
                {
                    if (group.Value[i] == '/')
                    {
                        y--;
                        x = 0;
                        continue;
                    }
                    if (x < 8)
                    {
                        if (char.IsLetter(group.Value[i]))
                        {
                            builder.pieces[y, x] = new Piece(group.Value[i]);
                            x++;
                        }
                        else if (char.IsDigit(group.Value[i]))
                        {
                            x += int.Parse(group.Value[i].ToString());
                        }
                    }
                }
                break;

            case "3":
                builder.Turn = PieceColor.FromChar(group.Value[0]);
                break;

            case "4":
                if (group.Value != "-")
                {
                    if (group.Value.Contains('K'))
                    {
                        builder.CastleWK = true;
                    }
                    if (group.Value.Contains('Q'))
                    {
                        builder.CastleWQ = true;
                    }
                    if (group.Value.Contains('k'))
                    {
                        builder.CastleBK = true;
                    }
                    if (group.Value.Contains('q'))
                    {
                        builder.CastleBQ = true;
                    }
                }
                break;

            case "5":
                if (group.Value == "-")
                {
                    builder.EnPassant = new();
                }
                else
                {
                    builder.EnPassant = new Position(group.Value);
                }
                break;

            case "6":
                (builder.HalfMoves, builder.FullMoves) = group.Value.Split(' ').Select(s => int.Parse(s)).ToArray();
                break;
            }
        }

        var wcap = new List <Piece>();
        var bcap = new List <Piece>();

        var fpieces = builder.pieces.Cast <Piece>().Where(p => p is not null);

        // Calculating missing pieces on according begin pieces in fen
        // Math.Clamp() for get max/min taken figures (2 queens possible)
        wcap.AddRange(Enumerable.Range(0, Math.Clamp(8 - fpieces.Where(p => p.Type == PieceType.Pawn && p.Color == PieceColor.White).Count(), 0, 8)).Select(_ => new Piece(PieceColor.White, PieceType.Pawn)));
        wcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Rook && p.Color == PieceColor.White).Count(), 0, 2)).Select(_ => new Piece(PieceColor.White, PieceType.Rook)));
        wcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Bishop && p.Color == PieceColor.White).Count(), 0, 2)).Select(_ => new Piece(PieceColor.White, PieceType.Bishop)));
        wcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Knight && p.Color == PieceColor.White).Count(), 0, 2)).Select(_ => new Piece(PieceColor.White, PieceType.Knight)));
        wcap.AddRange(Enumerable.Range(0, Math.Clamp(1 - fpieces.Where(p => p.Type == PieceType.Queen && p.Color == PieceColor.White).Count(), 0, 1)).Select(_ => new Piece(PieceColor.White, PieceType.Queen)));

        bcap.AddRange(Enumerable.Range(0, Math.Clamp(8 - fpieces.Where(p => p.Type == PieceType.Pawn && p.Color == PieceColor.Black).Count(), 0, 8)).Select(_ => new Piece(PieceColor.Black, PieceType.Pawn)));
        bcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Rook && p.Color == PieceColor.Black).Count(), 0, 2)).Select(_ => new Piece(PieceColor.Black, PieceType.Rook)));
        bcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Bishop && p.Color == PieceColor.Black).Count(), 0, 2)).Select(_ => new Piece(PieceColor.Black, PieceType.Bishop)));
        bcap.AddRange(Enumerable.Range(0, Math.Clamp(2 - fpieces.Where(p => p.Type == PieceType.Knight && p.Color == PieceColor.Black).Count(), 0, 2)).Select(_ => new Piece(PieceColor.Black, PieceType.Knight)));
        bcap.AddRange(Enumerable.Range(0, Math.Clamp(1 - fpieces.Where(p => p.Type == PieceType.Queen && p.Color == PieceColor.Black).Count(), 0, 1)).Select(_ => new Piece(PieceColor.Black, PieceType.Queen)));

        builder.WhiteCaptured = wcap.ToArray();
        builder.BlackCaptured = bcap.ToArray();

        return(true, null);
    }
Exemple #5
0
 /// <summary>
 /// Generates FEN string representing current board
 /// </summary>
 public string ToFen()
 {
     return(FenBoardBuilder.Load(this).ToString());
 }
Exemple #6
0
    public static (bool succeeded, ChessException?exception) TryLoad(string pgn, out ChessBoard?board)
    {
        board = new();

        var headersMatches = Regexes.regexHeaders.Matches(pgn);

        if (headersMatches.Count > 0)
        {
            // Extracting headers
            for (int i = 0; i < headersMatches.Count; i++)
            {
                // [Black "Geras1mleo"]
                // Groups[1] = Black
                // Groups[2] = Geras1mleo
                board.headers.Add(headersMatches[i].Groups[1].Value,
                                  headersMatches[i].Groups[2].Value);
            }
        }

        // San move can occur in header ex. in nickname of player => remove headers from string
        pgn = Regexes.regexHeaders.Replace(pgn, "");

        // Loading fen if exist
        if (board.headers.TryGetValue("FEN", out var fen))
        {
            var(succeeded, exception) = FenBoardBuilder.TryLoad(fen, out board.FenBuilder);

            if (!succeeded)
            {
                board = null;
                return(false, exception);
            }

            board.pieces = board.FenBuilder.Pieces;

            board.HandleKingChecked();
            board.HandleEndGame();

            if (board.IsEndGame)
            {
                return(true, null);
            }
        }

        // Remove all alternatives
        pgn = Regexes.regexAlternatives.Replace(pgn, "");

        // Remove all comments
        pgn = Regexes.regexComments.Replace(pgn, "");

        // Todo Save Alternative moves(bracnhes) and Comments for moves

        var movesMatches = Regexes.regexSanMoves.Matches(pgn);

        // Execute all found moves
        for (int i = 0; i < movesMatches.Count; i++)
        {
            var(succeeded, exception) = SanBuilder.TryParse(board, movesMatches[i].Value, out var move, true);

            if (!succeeded)
            {
                board = null;
                return(false, exception);
            }

            // If san parsing succeeded => move is valid

            board.executedMoves.Add(move);
            board.DropPieceToNewPosition(move);
            board.moveIndex = board.executedMoves.Count - 1;
        }


        board.HandleKingChecked();
        board.HandleEndGame();

        // If not actual end game but game is in fact ended => someone resigned
        if (!board.IsEndGame)
        {
            if (pgn.Contains("1-0"))
            {
                board.Resign(PieceColor.Black);
            }

            else if (pgn.Contains("0-1"))
            {
                board.Resign(PieceColor.White);
            }

            else if (pgn.Contains("1/2-1/2"))
            {
                board.Draw();
            }
        }

        return(true, null);
    }