コード例 #1
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);
        }
コード例 #2
0
ファイル: ChessDraw.cs プロジェクト: Bonifatius94/ChessAI.CS
        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);
        }
コード例 #3
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);
        }
コード例 #4
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);
        }
コード例 #5
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);
        }
コード例 #6
0
ファイル: ChessDraw.cs プロジェクト: Bonifatius94/ChessAI.CS
        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);
        }
コード例 #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)
        {
            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);
        }
コード例 #8
0
        private IEnumerable <ChessPosition> getStandardDrawPositions(ChessPosition position)
        {
            // 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>(position.Row - 1, position.Column - 1),
                new Tuple <int, int>(position.Row - 1, position.Column),
                new Tuple <int, int>(position.Row - 1, position.Column + 1),
                new Tuple <int, int>(position.Row, position.Column - 1),
                new Tuple <int, int>(position.Row, position.Column + 1),
                new Tuple <int, int>(position.Row + 1, position.Column - 1),
                new Tuple <int, int>(position.Row + 1, position.Column),
                new Tuple <int, int>(position.Row + 1, position.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.Item1, x.Item2));

            return(positions);
        }
コード例 #9
0
ファイル: ChessDraw.cs プロジェクト: Bonifatius94/ChessAI.CS
        private static int toHashCode(ChessDrawType drawType, ChessColor drawingSide, ChessPieceType drawingPieceType, ChessPieceType?takenPieceType,
                                      ChessPieceType?promotionPieceType, ChessPosition oldPosition, ChessPosition newPosition, bool isFirstMove)
        {
            // TODO: try to remove if/else branchings to make this more efficient

            // shift the bits to the right position (preparation for bitwise OR)
            int isFirstMoveBits        = (isFirstMove ? 1 : 0) << IS_FIRST_MOVE_TRAILING_BITS;
            int drawTypeBits           = ((int)drawType) << DRAW_TYPE_TRAILING_BITS;
            int drawingSideBits        = ((int)drawingSide) << DRAWING_SIDE_TRAILING_BITS;
            int drawingPieceTypeBits   = ((int)drawingPieceType) << DRAWING_PIECE_TYPE_TRAILING_BITS;
            int takenPieceTypeBits     = ((takenPieceType != null) ? (int)takenPieceType.Value : CHESS_PIECE_TYPE_NULL) << TAKEN_PIECE_TYPE_TRAILING_BITS;
            int promotionPieceTypeBits = ((promotionPieceType != null) ? (int)promotionPieceType.Value : CHESS_PIECE_TYPE_NULL) << PROMOTION_PIECE_TYPE_TRAILING_BITS;
            int oldPositionBits        = oldPosition.GetHashCode() << OLD_POSITION_TRAILING_BITS;
            int newPositionBits        = newPosition.GetHashCode();

            // fuse the shifted bits to the hash code (by bitwise OR)
            int hashCode = (isFirstMoveBits | drawTypeBits | drawingSideBits | drawingPieceTypeBits
                            | takenPieceTypeBits | promotionPieceTypeBits | oldPositionBits | newPositionBits);

            return(hashCode);
        }
コード例 #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 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);
        }
コード例 #11
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);
        }
コード例 #12
0
        private                ChessPosition[] serialize()
        {
            ulong posCache = _hash;

            // extract count and initialize result array
            byte count     = (byte)(posCache & 0xFuL);
            var  positions = new ChessPosition[count];

            // shift the cache to the first position
            posCache >>= 4;

            // loop through positions
            for (byte i = 0; i < count; i++)
            {
                // extract the position and apply it to the result array
                byte pos = (byte)(posCache & 0x3FuL);
                positions[i] = new ChessPosition(pos);

                // shift the cache to the next position
                posCache >>= 6;
            }

            return(positions);
        }
コード例 #13
0
 public ChessPieceAtPos(ChessPosition position, ChessPiece piece)
 {
     _hashCode = (short)((position.GetHashCode() << 5) | piece.GetHashCode());
 }
コード例 #14
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);
        }
コード例 #15
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);
        }