/// <summary>
        /// Parse a metadata draw from the given PGN content.
        /// </summary>
        /// <param name="game">The chess game with all previous draws.</param>
        /// <param name="content">The PGN content to be parsed.</param>
        /// <returns>The parsed metadata draw</returns>
        private ChessDraw?parseMetadataDraw(ChessGame game, string content)
        {
            ChessDraw?draw     = null;
            string    original = content;

            try
            {
                // remove not significant markups ('x', '+', '#', '=')
                content = content.Replace("x", "");
                content = content.Replace("+", "");
                content = content.Replace("#", "");
                content = content.Replace("=", "");

                // parse drawing piece type
                ChessPieceType type = (char.IsUpper(content[0])) ? parseType(content[0]) : ChessPieceType.Peasant;
                content = char.IsUpper(content[0]) ? content.Substring(1, content.Length - 1) : content;

                // parse promotion piece type
                ChessPieceType?promotionType = (char.IsUpper(content[content.Length - 1])) ? (ChessPieceType?)parseType(content[content.Length - 1]) : null;
                content = char.IsUpper(content[content.Length - 1]) ? content.Substring(0, content.Length - 1) : content;

                // parse row / column hints
                int hintRow;
                hintRow = (content.Length == 3 && int.TryParse(content.Substring(0, 1), out hintRow)) ? (hintRow - 1) : -1;
                int hintColumn = (content.Length == 3 && content[0] >= 'a' && content[0] <= 'h') ? (content[0] - 'a') : -1;
                content = (content.Length == 3) ? content.Substring(1, content.Length - 1) : content;

                // make sure that the content has only 2 characters left
                if (content.Length > 2 || !ChessPosition.AreCoordsValid(content))
                {
                    return(null);
                }

                // determine the old and new position of the drawing chess piece
                var newPos = new ChessPosition(content);

                // compute all possible allied draws
                var alliedDraws = game.GetDraws(true);

                // find the draw instance in the list of all possible draws
                draw = alliedDraws
                       .Where(x =>
                              x.DrawingPieceType == type && x.NewPosition == newPos && x.PeasantPromotionPieceType == promotionType &&
                              (hintRow == -1 || x.OldPosition.Row == hintRow) && (hintColumn == -1 || x.OldPosition.Column == hintColumn)
                              ).First();

                // TODO: implement parser logic for en-passant
            }
            catch (Exception)
            {
                Console.WriteLine($"unable to parse \"{ original }\"\n{ game.Board.ToString() }\n");
            }

            return(draw);
        }
Exemple #2
0
        private void testPeasantPromotion()
        {
            // simulate for white and black side
            for (int colorValue = 0; colorValue < 2; colorValue++)
            {
                var allyColor  = (ChessColor)colorValue;
                var enemyColor = allyColor.Opponent();

                // go through all columns where the promoting peasant is moving foreward
                for (int fwCol = 0; fwCol < 8; fwCol++)
                {
                    int fwRow = (allyColor == ChessColor.White) ? 6 : 1;
                    var fwPos = new ChessPosition(fwRow, fwCol);

                    var pieces = new List <ChessPieceAtPos>()
                    {
                        new ChessPieceAtPos(new ChessPosition(4, 0), new ChessPiece(ChessPieceType.King, ChessColor.White, true)),
                        new ChessPieceAtPos(new ChessPosition(4, 7), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)),
                        new ChessPieceAtPos(fwPos, new ChessPiece(ChessPieceType.Peasant, allyColor, true)),
                    };

                    int catchRow      = (allyColor == ChessColor.White) ? 7 : 0;
                    int leftCatchCol  = fwCol - 1;
                    int rightCatchCol = fwCol + 1;

                    var           enemyPeasant = new ChessPiece(ChessPieceType.Peasant, enemyColor, true);
                    ChessPosition posCatchLeft;
                    ChessPosition posCatchRight;

                    if (ChessPosition.AreCoordsValid(catchRow, leftCatchCol))
                    {
                        posCatchLeft = new ChessPosition(catchRow, leftCatchCol);
                        pieces.Add(new ChessPieceAtPos(posCatchLeft, enemyPeasant));
                    }

                    if (ChessPosition.AreCoordsValid(catchRow, rightCatchCol))
                    {
                        posCatchRight = new ChessPosition(catchRow, rightCatchCol);
                        pieces.Add(new ChessPieceAtPos(posCatchRight, enemyPeasant));
                    }

                    IChessBoard board = new ChessBoard(pieces);
                    var         draws = ChessDrawGenerator.Instance.GetDraws(board, fwPos, null, true);
                    Assert.True(draws.Count() == (4 * ((fwCol % 7 == 0) ? 2 : 3)));

                    foreach (var draw in draws)
                    {
                        board = new ChessBoard(pieces);
                        board = board.ApplyDraw(draw);
                        Assert.True(board.AllPieces.All(x => x.Piece.Color == enemyColor || x.Piece.Type != ChessPieceType.Peasant));
                    }
                }
            }
        }
        /// <summary>
        /// Make a human user put the next draw via CLI.
        /// </summary>
        /// <param name="board">The chess board representing the current game situation.</param>
        /// <param name="previousDraw">The preceding draw made by the enemy.</param>
        /// <returns>the next chess draw</returns>
        public ChessDraw GetNextDraw(IChessBoard board, ChessDraw?previousDraw)
        {
            ChessPosition  oldPosition;
            ChessPosition  newPosition;
            ChessPieceType?promotionPieceType = null;

            do
            {
                // get draw from user input
                Console.Write("Please make your next draw (e.g. 'e2-e4): ");
                string userInput = Console.ReadLine().Trim().ToLower();

                // parse user input
                if (userInput.Length == 5)
                {
                    // parse coord strings
                    string oldPosString = userInput.Substring(0, 2);
                    string newPosString = userInput.Substring(3, 2);

                    // validate coord strings
                    if (ChessPosition.AreCoordsValid(oldPosString) && ChessPosition.AreCoordsValid(newPosString))
                    {
                        // init chess positions
                        oldPosition = new ChessPosition(oldPosString);
                        newPosition = new ChessPosition(newPosString);

                        // make sure that the player possesses the the chess piece he is moving (simple validation)
                        if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Color == Side)
                        {
                            break;
                        }
                        else
                        {
                            Console.Write("There is no chess piece to be moved onto the field you put! ");
                        }
                    }
                }
                else
                {
                    Console.Write("Your input needs to be of the syntax in the example! ");
                }
            }while (true);

            // handle peasant promotion
            if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Type == ChessPieceType.Peasant &&
                (Side == ChessColor.White && newPosition.Row == 7) || (Side == ChessColor.Black && newPosition.Row == 0))
            {
                do
                {
                    // get draw from user input
                    Console.Write("You have put a promotion draw. Please choose the type you want to promote to (options: Bishop=B, Knight=N, Rook=R, Queen=Q): ");
                    string userInput = Console.ReadLine().Trim().ToLower().ToLower();

                    if (userInput.Length == 1)
                    {
                        switch (userInput[0])
                        {
                        case 'b': promotionPieceType = ChessPieceType.Bishop; break;

                        case 'n': promotionPieceType = ChessPieceType.Knight; break;

                        case 'r': promotionPieceType = ChessPieceType.Rook; break;

                        case 'q': promotionPieceType = ChessPieceType.Queen; break;
                        }

                        if (promotionPieceType == null)
                        {
                            Console.Write("Your input needs to be a letter like in the example! ");
                        }
                    }
                }while (promotionPieceType == null);
            }

            return(new ChessDraw(board, oldPosition, newPosition, promotionPieceType));
        }