예제 #1
0
        private IEnumerable <ChessDraw> getRochadeDraws(IChessBoard board, ChessColor drawingSide)
        {
            // TODO: do optimizations!!!

            // get enemy capturable positions
            var enemyKing = (drawingSide == ChessColor.White) ? board.BlackKing : board.WhiteKing;
            var enemyCapturablePositions =
                board.GetPiecesOfColor(drawingSide.Opponent()).Where(x => x.Piece.Type != ChessPieceType.King)
                .SelectMany(x => ChessDrawGenerator.Instance.GetDraws(board, x.Position, null, false)).Select(x => x.NewPosition)
                .Concat(getStandardDrawPositions(enemyKing.Position));

            // get the allied king and towers
            int row                = (drawingSide == ChessColor.White) ? 0 : 7;
            var alliedKing         = (drawingSide == ChessColor.White) ? board.WhiteKing : board.BlackKing;
            var farAlliedTowerPos  = new ChessPosition(row, 0);
            var farAlliedTower     = board.GetPieceAt(farAlliedTowerPos);
            var nearAlliedTowerPos = new ChessPosition(row, 7);
            var nearAlliedTower    = board.GetPieceAt(nearAlliedTowerPos);

            // define the fields that must not be capturable by the opponent
            var bigRochadeKingPassagePositions   = (drawingSide == ChessColor.White) ? whiteKingBigRochadePassagePositions   : blackKingBigRochadePassagePositions;
            var smallRochadeKingPassagePositions = (drawingSide == ChessColor.White) ? whiteKingSmallRochadePassagePositions : blackKingSmallRochadePassagePositions;

            bool canBigRochade =
                // check for preconditions of big rochade
                (board.IsCapturedAt(farAlliedTowerPos) && !alliedKing.Piece.WasMoved && !farAlliedTower.WasMoved &&
                 bigRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King)) &&
                 !board.IsCapturedAt(new ChessPosition(row, 1)))
                // make sure that no rochade field can be captured by the opponent
                && !enemyCapturablePositions.Any(pos => bigRochadeKingPassagePositions.Contains(pos));

            bool canSmallRochade =
                // check for preconditions of small rochade
                (board.IsCapturedAt(nearAlliedTowerPos) && !alliedKing.Piece.WasMoved && !nearAlliedTower.WasMoved &&
                 smallRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King)))
                // make sure that no rochade field can be captured by the opponent and the rochade field on the B-line is not captured
                && !enemyCapturablePositions.Any(pos => smallRochadeKingPassagePositions.Contains(pos));

            // write result draws
            int index      = 0;
            int drawsCount = (canSmallRochade ? 1 : 0) + (canBigRochade ? 1 : 0);

            ChessDraw[] draws = new ChessDraw[drawsCount];
            if (canSmallRochade)
            {
                draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 6));
            }
            if (canBigRochade)
            {
                draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 2));
            }

            return(draws);
        }
예제 #2
0
        /// <summary>
        /// Compute whether the draw is valid or not. If it is invalid, an exception with an according message is thrown.
        /// </summary>
        /// <param name="board">the chess board where the draw should be applied to</param>
        /// <param name="predecedingEnemyDraw">The last draw that the oponent made</param>
        /// <returns>boolean whether the draw is valid</returns>
        public bool IsValid(IChessBoard board, ChessDraw?predecedingEnemyDraw = null)
        {
            // TODO: refactor this function!!!

            // get the piece to be drawn
            var piece = board.GetPieceAt(OldPosition);

            // make sure that there is a chess piece of the correct color that can be drawn
            if (!board.IsCapturedAt(OldPosition))
            {
                throw new ArgumentException($"There is no chess piece on { OldPosition.FieldName }.");
            }
            if (piece.Color != DrawingSide)
            {
                throw new ArgumentException($"The chess piece on { OldPosition.FieldName } is owned by the opponent.");
            }

            // compute the possible chess draws for the given chess piece
            var possibleDraws = ChessDrawGenerator.Instance.GetDraws(board, OldPosition, predecedingEnemyDraw, true);

            // check if there is a possible draw with the same new position and type (this implies that the given draw is valid)
            var  type     = Type;
            var  position = NewPosition;
            bool ret      = (possibleDraws?.Count() > 0) && possibleDraws.Any(x => x.Type == type && x.NewPosition == position);

            return(ret);
        }
예제 #3
0
        private static ChessDrawType getDrawType(IChessBoard board, ChessPosition oldPos,
                                                 ChessPosition newPos, ChessPieceType?peasantPromotionType)
        {
            var piece = board.GetPieceAt(oldPos);
            var type  = ChessDrawType.Standard;

            // check for a peasant promotion
            if (peasantPromotionType != null && piece.Type == ChessPieceType.Peasant &&
                ((newPos.Row == 7 && piece.Color == ChessColor.White) ||
                 (newPos.Row == 0 && piece.Color == ChessColor.Black)))
            {
                type = ChessDrawType.PeasantPromotion;
            }
            // check for a rochade
            else if (piece.Type == ChessPieceType.King && Math.Abs(oldPos.Column - newPos.Column) == 2)
            {
                type = ChessDrawType.Rochade;
            }
            // check for an en-passant
            else if (piece.Type == ChessPieceType.Peasant && !board.IsCapturedAt(newPos) &&
                     Math.Abs(oldPos.Column - newPos.Column) == 1)
            {
                type = ChessDrawType.EnPassant;
            }

            return(type);
        }
예제 #4
0
        private IEnumerable <ChessDraw> getForewardDraws(IChessBoard board, ChessPosition drawingPiecePosition)
        {
            var draws = new List <ChessDraw>();
            var piece = board.GetPieceAt(drawingPiecePosition);

            var coordsPosOneForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column);
            var coordsPosTwoForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 2 : -2), drawingPiecePosition.Column);

            if (ChessPosition.AreCoordsValid(coordsPosOneForeward))
            {
                var  posOneForeward = new ChessPosition(coordsPosOneForeward);
                bool oneForeward    = !board.IsCapturedAt(posOneForeward);

                if (oneForeward)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posOneForeward));

                    if (!piece.WasMoved && ChessPosition.AreCoordsValid(coordsPosTwoForeward))
                    {
                        var posTwoForeward = new ChessPosition(coordsPosTwoForeward);

                        if (!board.IsCapturedAt(posTwoForeward))
                        {
                            draws.Add(new ChessDraw(board, drawingPiecePosition, posTwoForeward));
                        }
                    }
                }
            }

            return(draws);
        }
예제 #5
0
        public ChessDraw(IChessBoard board, ChessPosition oldPos, ChessPosition newPos, ChessPieceType?peasantPromotionType = null)
        {
            // get the drawing piece
            var piece = board.GetPieceAt(oldPos);

            // determine all property values
            var type             = getDrawType(board, oldPos, newPos, peasantPromotionType);
            var drawingSide      = piece.Color;
            var drawingPieceType = piece.Type;

            var takenPieceType =
                (type == ChessDrawType.EnPassant)
                    ? (ChessPieceType?)ChessPieceType.Peasant
                    : (board.IsCapturedAt(newPos) ? (ChessPieceType?)board.GetPieceAt(newPos).Type : null);

            // transform property values to a hash code
            _hashCode = toHashCode(type, drawingSide, drawingPieceType, takenPieceType, peasantPromotionType, oldPos, newPos, !piece.WasMoved);
        }
예제 #6
0
        public void UpdatePieces(IChessBoard board)
        {
            for (byte pos = 0; pos < 64; pos++)
            {
                var field = Fields[pos];
                field.UpdatePiece(board.IsCapturedAt(pos) ? (ChessPiece?)board.GetPieceAt(pos) : null);
            }

            _board = (IChessBoard)((ICloneable)board).Clone();
        }
예제 #7
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            // determine the drawing piece and the required draw generator
            var piece     = board.GetPieceAt(drawingPiecePosition);
            var generator = _explicitGenerators[piece.Type];

            // compute all possible chess draws for the given chess piece
            var draws = generator.GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck).ToArray();

            return(draws);
        }
예제 #8
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is a knight
            if (piece.Type != ChessPieceType.Knight)
            {
                throw new InvalidOperationException("The chess piece is not a knight.");
            }

            // get positions next to the current position of the king (all permutations of { -1, 0, +1 }^2 except (0, 0))
            var coords = new Tuple <int, int>[]
            {
                new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column - 1),
                new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column + 1),
                new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column - 2),
                new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column + 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column - 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column + 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column - 1),
                new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column + 1),
            };

            // only retrieve positions that are actually onto the chess board (and not off scale)
            var positions = coords.Where(x => ChessPosition.AreCoordsValid(x)).Select(x => new ChessPosition(x));

            // do not draw into positions captured by allied chess pieces
            positions = positions.Where(x => !board.IsCapturedAt(x) || board.GetPieceAt(x).Color != piece.Color);

            // transform positions to chess draws
            var draws = positions.Select(newPos => new ChessDraw(board, drawingPiecePosition, newPos));

            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                // remove draws that would draw into a check situation
                draws = draws.Where(x => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, x));
            }

            return(draws);
        }
예제 #9
0
        private double getKnightScore(IChessBoard board, ChessPosition position)
        {
            // Shannon's chess piece evaluation
            // TODO: check this heuristic

            double score = BASE_SCORE_KNIGHT;

            // bonus for developing and gained mobility
            if (board.GetPieceAt(position).WasMoved)
            {
                score += getMovabilityBonus(board, position);
            }

            return(score);
        }
예제 #10
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is a queen
            if (piece.Type != ChessPieceType.Queen)
            {
                throw new InvalidOperationException("The chess piece is not a queen.");
            }

            // combine the positions that a rock or a bishop could capture
            var draws =
                new RookChessDrawGenerator().GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck)
                .Union(new BishopChessDrawGenerator().GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck));

            return(draws);
        }
예제 #11
0
        /// <summary>
        /// Help converting a chess board instance to a hash string.
        /// </summary>
        /// <param name="board">the chess board to be converted</param>
        /// <returns>a hash string containing the data from the chess board</returns>
        public static Bitboard ToBitboard(this IChessBoard board)
        {
            // init a new bitboard with 40 byte
            var bitboard = new Bitboard(40 * 8);

            // loop through all chess positions
            for (byte pos = 0; pos < 64; pos++)
            {
                // get the chess piece bits
                var  position  = new ChessPosition(pos);
                byte pieceCode = (byte)(board.GetPieceAt(position).GetHashCode() << 3);

                // apply bits to bitboard
                bitboard.SetBitsAt(pos * 5, pieceCode, 5);
            }

            return(bitboard);
        }
예제 #12
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is a king
            if (piece.Type != ChessPieceType.King)
            {
                throw new InvalidOperationException("The chess piece is not a king.");
            }

            // get the possible draw positions
            var positions = getStandardDrawPositions(drawingPiecePosition);

            // only retrieve positions that are not captured by an allied chess piece
            var alliedPieces = board.GetPiecesOfColor(piece.Color);

            positions = positions.Except(alliedPieces.Select(x => x.Position));

            // only retrieve positions that cannot be captured by the enemy king (-> avoid draw into check)
            var enemyKing             = piece.Color == ChessColor.White ? board.BlackKing : board.WhiteKing;
            var enemyKingDrawPositons = getStandardDrawPositions(enemyKing.Position);

            positions = positions.Except(enemyKingDrawPositons);

            // transform positions to draws
            IEnumerable <ChessDraw> draws = positions.Select(newPos => new ChessDraw(board, drawingPiecePosition, newPos)).ToArray();

            // analyze draw into a check situation
            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                draws = draws.Where(draw => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw)).ToArray();
            }

            // add rochade draws
            bool canRochade = (drawingPiecePosition == new ChessPosition("E1") || drawingPiecePosition == new ChessPosition("E8"));

            if (canRochade)
            {
                draws = draws.Concat(getRochadeDraws(board, piece.Color));
            }

            return(draws);
        }
예제 #13
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is a king
            if (piece.Type != ChessPieceType.Peasant)
            {
                throw new InvalidOperationException("The chess piece is not a peasant.");
            }

            // get all possible draws
            var draws = getForewardDraws(board, drawingPiecePosition).Union(getCatchDraws(board, drawingPiecePosition, precedingEnemyDraw));

            // handle peasant promotion
            draws = draws.SelectMany(x => {
                // check if the chess draw is a peasant promotion
                if ((x.NewPosition.Row == 7 && piece.Color == ChessColor.White) || (x.NewPosition.Row == 0 && piece.Color == ChessColor.Black))
                {
                    // return all 4 promotion options for the input draw
                    return(new ChessDraw[]
                    {
                        new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Queen),
                        new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Rook),
                        new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Bishop),
                        new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Knight),
                    });
                }

                // return the input draw unchanged
                return(new ChessDraw[] { x });
            });

            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                // remove draws that would draw into a check situation
                draws = draws.Where(x => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, x));
            }

            return(draws);
        }
예제 #14
0
        private double getPeasantScore(IChessBoard board, ChessPosition position)
        {
            // Shannon's chess piece evaluation
            // TODO: check this heuristic

            double score = BASE_SCORE_PEASANT;
            var    piece = board.GetPieceAt(position);

            // bonus the more the peasant advances (but don't punish if peasant is not drawn)
            int advanceFactor = (piece.Color == ChessColor.White) ? (position.Row - 2) : (5 - position.Row);

            if (advanceFactor > 0)
            {
                score += advanceFactor * 0.04;
            }

            //// bonus for connected peasants / malus for an isolated peasant
            //int protectedRow = (piece.Color == ChessColor.White) ? (position.Row + 1) : (position.Row - 1);
            //var posLeft = new ChessPosition(protectedRow, position.Column - 1);
            //var posRight = new ChessPosition(protectedRow, position.Column + 1);
            //bool isConnected =
            //       (ChessPosition.AreCoordsValid(protectedRow, position.Column - 1) && board.IsCapturedAt(posLeft) && board.GetPieceAt(posLeft).Color == piece.Color)
            //    || (ChessPosition.AreCoordsValid(protectedRow, position.Column + 1) && board.IsCapturedAt(posRight) && board.GetPieceAt(posRight).Color == piece.Color);
            //score += (isConnected ? 1 : -1) * 0.05;

            //// malus for doubled peasants
            //bool isDoubled = board.GetPiecesOfColor(piece.Color).Any(x => x.Piece.Type == ChessPieceType.Peasant && x.Position.Column == position.Column && x.Position.Row != position.Row);
            //if (isConnected) { score -= 0.1; }

            //// malus if peasant was passed by an enemy peasant
            //bool isPassed = board.GetPiecesOfColor(piece.Color.Opponent()).Any(x =>
            //    x.Piece.Type == ChessPieceType.Peasant && Math.Abs(x.Position.Column - position.Column) == 1
            //    && ((x.Position.Row < position.Row && x.Piece.Color == ChessColor.White) || (x.Position.Row > position.Row && x.Piece.Color == ChessColor.Black))
            //);
            //if (isPassed) { score -= 0.1; }

            return(score);
        }
예제 #15
0
        private double getPieceScore(IChessBoard board, ChessPosition position)
        {
            double score;
            var    piece = board.GetPieceAt(position);

            switch (piece.Type)
            {
            case ChessPieceType.King:    score = getKingScore(board, position);    break;

            case ChessPieceType.Queen:   score = getQueenScore(board, position);   break;

            case ChessPieceType.Rook:    score = getRookScore(board, position);    break;

            case ChessPieceType.Bishop:  score = getBishopScore(board, position);  break;

            case ChessPieceType.Knight:  score = getKnightScore(board, position);  break;

            case ChessPieceType.Peasant: score = getPeasantScore(board, position); break;

            default: throw new ArgumentException("unknown chess piece type detected!");
            }

            return(score);
        }
        private double getPieceScore(IChessBoard board, ChessPosition position)
        {
            double score;
            var    piece = board.GetPieceAt(position);

            switch (piece.Type)
            {
            case ChessPieceType.King:    score = BASE_SCORE_KING;    break;

            case ChessPieceType.Queen:   score = BASE_SCORE_QUEEN;   break;

            case ChessPieceType.Rook:    score = BASE_SCORE_ROOK;    break;

            case ChessPieceType.Bishop:  score = BASE_SCORE_BISHOP;  break;

            case ChessPieceType.Knight:  score = BASE_SCORE_KNIGHT;  break;

            case ChessPieceType.Peasant: score = BASE_SCORE_PEASANT; break;

            default: throw new ArgumentException("unknown chess piece type detected!");
            }

            return(score);
        }
예제 #17
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is bishop-like
            if (piece.Type != ChessPieceType.Bishop && piece.Type != ChessPieceType.Queen)
            {
                throw new InvalidOperationException("The chess piece is not a bishop.");
            }

            var draws = new List <ChessDraw>();

            // get upper left-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column - i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get lower left-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column - i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get upper right-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column + i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get lower right-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column + i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // analyze draw into a check situation
            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                draws = draws.Where(draw => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw)).ToList();
            }

            return(draws);
        }
예제 #18
0
        /// <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));
        }
예제 #19
0
        private IEnumerable <ChessDraw> getCatchDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null)
        {
            var draws = new List <ChessDraw>();
            var piece = board.GetPieceAt(drawingPiecePosition);

            // get the possible chess field positions (info: right / left from the point of view of the white side player)
            var coordsPosCatchLeft  = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column + 1);
            var coordsPosCatchRight = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column - 1);

            // check for en-passant precondition
            bool wasLastDrawPeasantDoubleForeward =
                precedingEnemyDraw != null && precedingEnemyDraw.Value.DrawingPieceType == ChessPieceType.Peasant &&
                Math.Abs(precedingEnemyDraw.Value.OldPosition.Row - precedingEnemyDraw.Value.NewPosition.Row) == 2;

            // check if left catch / en-passant is possible
            if (ChessPosition.AreCoordsValid(coordsPosCatchLeft))
            {
                var posCatchLeft = new ChessPosition(coordsPosCatchLeft);

                bool catchLeft = board.IsCapturedAt(posCatchLeft) && board.GetPieceAt(posCatchLeft).Color != piece.Color;
                if (catchLeft)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft));
                }

                if (wasLastDrawPeasantDoubleForeward)
                {
                    // get the positions of an enemy chess piece taken by a possible en-passant
                    var posEnPassantEnemyLeft = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column + 1);

                    bool isLeftFieldCapturedByEnemy =
                        precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyLeft && board.IsCapturedAt(posEnPassantEnemyLeft) &&
                        board.GetPieceAt(posEnPassantEnemyLeft).Color != piece.Color;

                    bool enPassantLeft = isLeftFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyLeft.Column - drawingPiecePosition.Column) == 1;
                    if (enPassantLeft)
                    {
                        draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft));
                    }
                }
            }

            // check if right catch / en-passant is possible
            if (ChessPosition.AreCoordsValid(coordsPosCatchRight))
            {
                var posCatchRight = new ChessPosition(coordsPosCatchRight);

                bool catchRight = board.IsCapturedAt(posCatchRight) && board.GetPieceAt(posCatchRight).Color != piece.Color;
                if (catchRight)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight));
                }

                if (wasLastDrawPeasantDoubleForeward)
                {
                    // get the positions of an enemy chess piece taken by a possible en-passant
                    var posEnPassantEnemyRight = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column - 1);

                    bool isRightFieldCapturedByEnemy =
                        precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyRight &&
                        board.IsCapturedAt(posEnPassantEnemyRight) && board.GetPieceAt(posEnPassantEnemyRight).Color != piece.Color;

                    bool enPassantRight = isRightFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyRight.Column - drawingPiecePosition.Column) == 1;
                    if (enPassantRight)
                    {
                        draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight));
                    }
                }
            }

            return(draws);
        }