private ChessDraw[] sortByScoreDesc(ChessDrawScore[] ratedDraws)
        {
            // TODO: check if this performs well

            // use in-place insertion sort (this has a bad performance of O(n^2),
            // but can be cached well for small arrays with ~50 items)
            // never use this sort algorithm for bigger data sets!!!

            // init result set of the same size as input
            var result = new ChessDraw[ratedDraws.Length];

            // loop through all elements
            for (int i = 0; i < ratedDraws.Length; i++)
            {
                // determine the max. item from the unsorted partition
                int maxIndex = indexOfMax(ratedDraws, i);

                // copy the item to the sorted partition
                result[i] = ratedDraws[maxIndex].Draw;

                // keep the unsorted element at offset index inside of the
                // unsorted partition, so it eventually gets sorted in
                ratedDraws[maxIndex] = ratedDraws[i];
            }

            return(result);
        }
        public double RateDraw(IChessBoard board, ChessDraw draw, int searchDepth)
        {
            // simulate the given draw
            var simulatedBoard = board.ApplyDraw(draw);

            // use the minimax algorithm to rate the score of the given draw
            double score = negamax(simulatedBoard, draw, searchDepth - 1, double.MinValue, double.MaxValue, false) * -1;

            return(score);
        }
        private void testEnPassant()
        {
            // simulate for white and black side
            for (int dfwColorValue = 0; dfwColorValue < 2; dfwColorValue++)
            {
                var dfwColor = (ChessColor)dfwColorValue;
                var epColor  = dfwColor.Opponent();

                // get the column where the peasant is moving foreward
                for (int fwCol = 0; fwCol < 8; fwCol++)
                {
                    int dfwRow    = (dfwColor == ChessColor.White) ? 1 : 6;
                    int attRow    = (dfwColor == ChessColor.White) ? 3 : 4;
                    var dfwOldPos = new ChessPosition(dfwRow, fwCol);
                    var dfwNewPos = new ChessPosition(attRow, fwCol);

                    // get the column where the en-passant peasant is placed
                    for (int attCol = 0; attCol < 8; attCol++)
                    {
                        if (fwCol != attCol)
                        {
                            var attOldPos = new ChessPosition(attRow, attCol);
                            var attNewPos = new ChessPosition(attRow + ((dfwColor == ChessColor.White) ? -1 : 1), fwCol);

                            var pieces = new List <ChessPieceAtPos>()
                            {
                                new ChessPieceAtPos(dfwOldPos, new ChessPiece(ChessPieceType.Peasant, dfwColor, false)),
                                new ChessPieceAtPos(attOldPos, new ChessPiece(ChessPieceType.Peasant, epColor, true)),
                                new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, false)),
                                new ChessPieceAtPos(new ChessPosition(7, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, false)),
                            };

                            // apply the double foreward draw as preparation for the en-passant
                            IChessBoard board   = new ChessBitboard(new ChessBoard(pieces));
                            var         drawDfw = new ChessDraw(board, dfwOldPos, dfwNewPos);
                            board = board.ApplyDraw(drawDfw);

                            // create the en-passant draw and validate it
                            var  drawEp            = new ChessDraw(board, attOldPos, attNewPos);
                            bool shouldDrawBeValid = Math.Abs(attCol - fwCol) == 1;
                            bool isDrawValid       = drawEp.IsValid(board, drawDfw);
                            Assert.True(shouldDrawBeValid == isDrawValid);

                            if (shouldDrawBeValid)
                            {
                                // check if the en-passant draw gets correctly applied to the chess board
                                board = board.ApplyDraw(drawEp);
                                Assert.True(!board.IsCapturedAt(dfwNewPos) && board.GetPieceAt(attNewPos) == pieces[1].Piece);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Parse a rochade 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 rochade draw</returns>
        private ChessDraw?parseRochade(ChessGame game, string content)
        {
            int row    = (game.SideToDraw == ChessColor.White) ? 0 : 7;
            int column = content.Equals(LITTLE_ROCHADE) ? 6 : 2;

            var oldPos = new ChessPosition(row, 4);
            var newPos = new ChessPosition(row, column);

            ChessDraw?draw = new ChessDraw(game.Board, oldPos, newPos);

            return(draw);
        }
        public void IsDrawIntoCheckTest()
        {
            // test this for both black and white chess pieces
            for (int colorValue = 0; colorValue < 2; colorValue++)
            {
                var allyColor  = (ChessColor)colorValue;
                var enemyColor = allyColor.Opponent();

                var pieceXNewPos = new Dictionary <ChessPieceType, ChessPosition>()
                {
                    { ChessPieceType.Queen, new ChessPosition(4, 4) },
                    { ChessPieceType.Rook, new ChessPosition(4, 4) },
                    { ChessPieceType.Bishop, new ChessPosition(4, 5) },
                    { ChessPieceType.Knight, new ChessPosition(5, 3) },
                    { ChessPieceType.Peasant, new ChessPosition(((allyColor == ChessColor.White) ? 4 : 2), 4) },
                };

                // go through all drawing chess piece types (except king; king is already tested in king draws unit test)
                for (int pieceTypeValue = 2; pieceTypeValue < 7; pieceTypeValue++)
                {
                    var pieceType = (ChessPieceType)pieceTypeValue;

                    // simulate situations with and without attacker (positive and negative test)
                    for (int putAttackerValue = 0; putAttackerValue < 2; putAttackerValue++)
                    {
                        bool putAttacker = (putAttackerValue == 1);
                        var  oldPos      = new ChessPosition(3, 4);

                        var pieces = new List <ChessPieceAtPos>()
                        {
                            new ChessPieceAtPos(oldPos, new ChessPiece(pieceType, allyColor, true)),
                            new ChessPieceAtPos(new ChessPosition(0, 7), new ChessPiece(ChessPieceType.King, allyColor, true)),
                            new ChessPieceAtPos(new ChessPosition(7, 5), new ChessPiece(ChessPieceType.King, enemyColor, true)),
                        };

                        if (putAttacker)
                        {
                            pieces.Add(new ChessPieceAtPos(new ChessPosition(7, 0), new ChessPiece(ChessPieceType.Bishop, enemyColor, true)));
                        }

                        var board = new ChessBoard(pieces);
                        var draw  = new ChessDraw(board, oldPos, pieceXNewPos[pieceType]);

                        bool shouldBeDrawIntoCheck = putAttacker;
                        bool isDrawIntoCheck       = ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw);
                        Assert.True(shouldBeDrawIntoCheck == isDrawIntoCheck);
                    }
                }
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Try to submit the a chess draw if it is valid.
        /// </summary>
        /// <param name="draw">The draw to be submitted</param>
        /// <returns>a boolean indicating whether the submitted chess draw is valid</returns>
        public bool TrySubmitDraw(ChessDraw draw)
        {
            // try to apply the chess draw
            bool success = _game.ApplyDraw(draw, true);

            // release the mutex of the waiting
            if (success && _isWaiting)
            {
                _isWaiting = false;
                _mutexWait.ReleaseMutex();
            }

            return(success);
        }
        private ChessDraw[] generateDraws(IChessBoard board, ChessDraw?lastDraw = null)
        {
            ChessDraw[] draws       = new ChessDraw[0];
            var         drawingSide = lastDraw?.DrawingSide.Opponent() ?? ChessColor.White;

            if (board?.GetType() == typeof(ChessBoard))
            {
                var alliedPieces = board.GetPiecesOfColor(drawingSide);
                draws = alliedPieces.SelectMany(x => ChessDrawGenerator.Instance.GetDraws(board, x.Position, lastDraw, true)).ToArray();
            }
            else if (board?.GetType() == typeof(ChessBitboard))
            {
                draws = ((ChessBitboard)board).GetAllDraws(drawingSide, lastDraw, true);
            }

            return(draws);
        }
        public ActionResult SubmitDraw(int id, [FromBody] ChessDraw draw)
        {
            // make sure the game with the given id exists
            if (!MatchmakingDispatcher.Matches.ContainsKey(id))
            {
                throw new ArgumentException($"game with id { id } does not exist!");
            }

            // submit the ches draw if valid
            var  matchmaker = MatchmakingDispatcher.Matches[id];
            bool isValid    = matchmaker.TrySubmitDraw(draw);

            // send a response whether the submitted draw could be applied
            var result = isValid ? Ok() as ActionResult : BadRequest();

            return(result);
        }
Esempio n. 9
0
        public async Task <bool> TrySubmitDraw(int gameId, ChessDraw draw)
        {
            bool ret = false;

            using (var client = new HttpClient())
            {
                string json = JsonConvert.SerializeObject(draw);

                using (var content = new StringContent(json))
                {
                    var response = await client.PutAsync($"{ _baseAddress }/{ API_CONTROLLER }/{ gameId }", content);

                    ret = response.IsSuccessStatusCode;
                }
            }

            return(ret);
        }
        private ChessGame prepareGame(List <Tuple <ChessPosition, ChessPosition> > moves)
        {
            // init a chess board in start formation
            var       game     = new ChessGame();
            ChessDraw lastDraw = new ChessDraw();

            // apply the moves to the chess board
            foreach (var move in moves)
            {
                lastDraw = new ChessDraw(game.Board, move.Item1, move.Item2);
                game.ApplyDraw(lastDraw);

                var status = ChessDrawSimulator.Instance.GetCheckGameStatus(game.Board, lastDraw);
                Assert.True(status == ChessGameStatus.Check || status == ChessGameStatus.None);
            }

            return(game);
        }
Esempio n. 11
0
        public void PassDraw(ChessDraw draw)
        {
            // cache the draw to be passed to the session
            _temp = draw;

            // release the mutex that makes GetNextDraw wait -> signal that the draw was made
            _canGetNextDraw = false;
            _mutex.ReleaseMutex();

            // make sure that GetNextDraw captures the mutex first
            while (_canGetNextDraw)
            {
                Thread.Sleep(10);
            }

            // recapture mutex, so the next invokation of GetNextDraw can wait again
            _mutex.WaitOne();
            _canGetNextDraw = true;
        }
Esempio n. 12
0
        /// <summary>
        /// Try to submit the next chess draw.
        /// </summary>
        /// <param name="draw">the chess draw to be submitted</param>
        /// <param name="timeout">the timeout in seconds</param>
        /// <returns>a boolean indicating whether the submission was successful</returns>
        public bool SubmitDraw(ChessDraw draw, int timeout = 300)
        {
            bool success = false;

            // try to submit out chess draw
            try
            {
                var submitDrawTask = httpHelper.TrySubmitDraw(_gameInfo.GameId, draw);
                success = (submitDrawTask.Wait(timeout * 1000) && submitDrawTask.Result);

                // apply the draw to the chess game instance if transmission was successfuls
                if (success)
                {
                    Game.ApplyDraw(draw);
                }
            }
            catch (Exception) { /* nothing to do here ... */ }

            return(success);
        }
Esempio n. 13
0
        public void CommonDrawsTest()
        {
            // create board in start formation
            var board = ChessBitboard.StartFormation;

            // draw white peasant E2-E4
            var posE2 = new ChessPosition("E2");
            var posE4 = new ChessPosition("E4");

            Assert.True(board.IsCapturedAt(posE2) && board.GetPieceAt(posE2) == new ChessPiece(ChessPieceType.Peasant, ChessColor.White, false));
            var draw = new ChessDraw(board, posE2, posE4);

            Assert.True(draw.IsFirstMove);
            board = (ChessBitboard)board.ApplyDraw(draw);
            Assert.True(!board.IsCapturedAt(posE2) && board.IsCapturedAt(posE4) && board.GetPieceAt(posE4) == new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true));

            // draw black peasant H7-H5
            var posH7 = new ChessPosition("H7");
            var posH5 = new ChessPosition("H5");

            board = (ChessBitboard)board.ApplyDraw(new ChessDraw(board, posH7, posH5));
            Assert.True(!board.IsCapturedAt(posH7) && board.IsCapturedAt(posH5) && board.GetPieceAt(posH5) == new ChessPiece(ChessPieceType.Peasant, ChessColor.Black, true));
        }
Esempio n. 14
0
        public void ConstructorAndGetterSetterTest()
        {
            // check if all possible chess draws can be created
            for (int firstMove = 0; firstMove < 2; firstMove++)
            {
                bool isFirstMove = firstMove == 1;

                for (int drawingSideValue = 0; drawingSideValue < 2; drawingSideValue++)
                {
                    var drawingSide = (ChessColor)drawingSideValue;

                    for (int drawTypeValue = 0; drawTypeValue < 4; drawTypeValue++)
                    {
                        var drawType = (ChessDrawType)drawTypeValue;

                        for (int drawingPieceTypeValue = 1; drawingPieceTypeValue < 7; drawingPieceTypeValue++)
                        {
                            var drawingPieceType = (ChessPieceType)drawingPieceTypeValue;

                            for (int takenPieceTypeValue = 0; takenPieceTypeValue < 7; takenPieceTypeValue++)
                            {
                                var takenPieceType = (takenPieceTypeValue > 0) ? (ChessPieceType?)((ChessPieceType)takenPieceTypeValue) : null;

                                for (int promotionPieceTypeValue = 0; promotionPieceTypeValue < 7; promotionPieceTypeValue++)
                                {
                                    var promotionPieceType = (promotionPieceTypeValue > 0) ? (ChessPieceType?)((ChessPieceType)promotionPieceTypeValue) : null;

                                    for (int oldPosHash = 0; oldPosHash < 64; oldPosHash++)
                                    {
                                        var oldPos = new ChessPosition((byte)oldPosHash);

                                        for (int newPosHash = 0; newPosHash < 64; newPosHash++)
                                        {
                                            var newPos = new ChessPosition((byte)newPosHash);

                                            // get expected hash code
                                            int hashCode = ((firstMove << 24) | (drawingSideValue << 23) | (drawTypeValue << 21) | (drawingPieceTypeValue << 18)
                                                            | (takenPieceTypeValue << 15) | (promotionPieceTypeValue << 12) | (oldPosHash << 6) | (newPosHash));

                                            // create a new chess draw instance and check if the getters work correctly
                                            var draw = new ChessDraw(hashCode);

                                            // check if the created chess draw has the correct features
                                            Assert.True(
                                                draw.IsFirstMove == isFirstMove && draw.DrawingSide == drawingSide && draw.Type == drawType && draw.DrawingPieceType == drawingPieceType && draw.TakenPieceType == takenPieceType &&
                                                draw.PeasantPromotionPieceType == promotionPieceType && draw.OldPosition == oldPos && draw.NewPosition == newPos && draw.GetHashCode() == hashCode
                                                );
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // test if several invalid chess draws are rejected
            try
            {
                // create invalid chess draw (should throw an exception)
                new ChessDraw(-1);
                Assert.True(false);
            }
            catch (Exception) { /* nothing to do here ... */ }

            try
            {
                // create invalid chess draw (should throw an exception)
                new ChessDraw(2097152);
                Assert.True(false);
            }
            catch (Exception) { /* nothing to do here ... */ }
        }
Esempio n. 15
0
        private void testOneAndDoubleForeward()
        {
            // simulate for white and black side
            for (int dfwColorValue = 0; dfwColorValue < 2; dfwColorValue++)
            {
                var allyColor = (ChessColor)dfwColorValue;

                // get the column where the peasant is moving foreward
                for (int col = 0; col < 8; col++)
                {
                    int oldRow    = (allyColor == ChessColor.White) ? 1 : 6;
                    int sfwNewRow = (allyColor == ChessColor.White) ? 2 : 5;
                    int dfwNewRow = (allyColor == ChessColor.White) ? 3 : 4;
                    var oldPos    = new ChessPosition(oldRow, col);
                    var sfwNewPos = new ChessPosition(sfwNewRow, col);
                    var dfwNewPos = new ChessPosition(dfwNewRow, col);

                    // check if the draw is only valid if the peasant was not already moved
                    for (int wasMovedValue = 0; wasMovedValue < 2; wasMovedValue++)
                    {
                        var wasMoved = (wasMovedValue == 1);

                        // check if blocking pieces of both colors are taken in consideration
                        for (int blockingPieceRowDiff = 2; blockingPieceRowDiff < 4; blockingPieceRowDiff++)
                        {
                            int blockRow = (allyColor == ChessColor.White) ? (oldRow + blockingPieceRowDiff) : (oldRow - blockingPieceRowDiff);
                            var blockPos = new ChessPosition(blockRow, col);

                            for (int bpColorValue = 0; bpColorValue < 2; bpColorValue++)
                            {
                                var bpColor = (ChessColor)bpColorValue;
                                output.WriteLine($"testing constellation: allyColor={ allyColor }, sfwNewPos={ sfwNewPos }, dfwNewPos={ dfwNewPos }, blockPos={ blockPos }, wasMoved={ wasMoved }");

                                var pieces = new List <ChessPieceAtPos>()
                                {
                                    new ChessPieceAtPos(oldPos, new ChessPiece(ChessPieceType.Peasant, allyColor, wasMoved)),
                                    new ChessPieceAtPos(blockPos, new ChessPiece(ChessPieceType.Peasant, bpColor, wasMoved)),
                                    new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, false)),
                                    new ChessPieceAtPos(new ChessPosition(7, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, false)),
                                };

                                bool shouldSfwBeValid = (blockingPieceRowDiff > 1);
                                bool shouldDfwBeValid = (wasMoved == false) && (blockingPieceRowDiff > 2);

                                // test draw-gen
                                var board = new ChessBitboard(new ChessBoard(pieces));
                                var draws = board.GetAllDraws(allyColor, null, true);

                                // validate draws
                                var  sfwDraw    = new ChessDraw(board, oldPos, sfwNewPos);
                                bool isSfwValid = sfwDraw.IsValid(board);
                                Assert.True(shouldSfwBeValid == isSfwValid);
                                var  dfwDraw    = new ChessDraw(board, oldPos, dfwNewPos);
                                bool isDfwValid = dfwDraw.IsValid(board);
                                Assert.True(shouldDfwBeValid == isDfwValid);

                                if (isSfwValid)
                                {
                                    Assert.Contains(sfwDraw, draws);

                                    // check if the chess piece is moved correctly
                                    var pieceCmp = new ChessPiece(ChessPieceType.Peasant, allyColor, true);
                                    var simBoard = board.ApplyDraw(sfwDraw);
                                    Assert.True(!simBoard.IsCapturedAt(oldPos) && simBoard.GetPieceAt(sfwNewPos) == pieceCmp);
                                }
                                else
                                {
                                    Assert.DoesNotContain(sfwDraw, draws);
                                }

                                if (isDfwValid)
                                {
                                    Assert.Contains(dfwDraw, draws);

                                    // check if the chess piece is moved correctly
                                    var pieceCmp = new ChessPiece(ChessPieceType.Peasant, allyColor, !wasMoved);
                                    var simBoard = board.ApplyDraw(dfwDraw);
                                    Assert.True(!simBoard.IsCapturedAt(oldPos) && simBoard.GetPieceAt(dfwNewPos) == pieceCmp);
                                }
                                else
                                {
                                    Assert.DoesNotContain(dfwDraw, draws);
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 16
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="board"></param>
 /// <param name="draw"></param>
 /// <param name="searchDepth"></param>
 /// <returns></returns>
 public double RateDraw(IChessBoard board, ChessDraw draw, int searchDepth)
 {
     return(MinimaxChessDrawAI.Instance.RateDraw(board, draw, searchDepth));
 }
        public void GetCheckGameStatusTest()
        {
            // test no check
            IChessBoard board     = ChessBoard.StartFormation;
            var         enemyDraw = new ChessDraw(board, new ChessPosition(0, 0), new ChessPosition(0, 0));

            board = board.ApplyDraw(enemyDraw);
            Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.None);

            // test simple check
            var pieces = new List <ChessPieceAtPos>()
            {
                new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)),
                new ChessPieceAtPos(new ChessPosition(1, 5), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)),
                new ChessPieceAtPos(new ChessPosition(7, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)),
                new ChessPieceAtPos(new ChessPosition(7, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)),
            };

            board     = new ChessBoard(pieces);
            enemyDraw = new ChessDraw(board, new ChessPosition(7, 3), new ChessPosition(6, 4));
            board     = board.ApplyDraw(enemyDraw);
            Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Check);

            // test checkmate
            for (int putSavingPieceValue = 0; putSavingPieceValue < 2; putSavingPieceValue++)
            {
                pieces = new List <ChessPieceAtPos>()
                {
                    new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)),
                    new ChessPieceAtPos(new ChessPosition(6, 1), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)),
                    new ChessPieceAtPos(new ChessPosition(2, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)),
                    new ChessPieceAtPos(new ChessPosition(2, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)),
                };

                // allow the ally to avoid the checkmate by putting an additional chess piece on the board
                // and test if the simulator makes use of this opportunity
                bool putSavingPiece = (putSavingPieceValue == 1);
                if (putSavingPiece)
                {
                    pieces.Add(new ChessPieceAtPos(new ChessPosition(1, 7), new ChessPiece(ChessPieceType.Rook, ChessColor.White, true)));
                }

                board     = new ChessBoard(pieces);
                enemyDraw = new ChessDraw(board, new ChessPosition(2, 3), new ChessPosition(1, 4));
                board     = board.ApplyDraw(enemyDraw);

                Assert.True(
                    (!putSavingPiece && ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Checkmate) ||
                    (putSavingPiece && ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Check)
                    );
            }

            // test stalemate
            pieces = new List <ChessPieceAtPos>()
            {
                new ChessPieceAtPos(new ChessPosition(0, 4), new ChessPiece(ChessPieceType.King, ChessColor.White, true)),
                new ChessPieceAtPos(new ChessPosition(6, 1), new ChessPiece(ChessPieceType.Peasant, ChessColor.White, true)),
                new ChessPieceAtPos(new ChessPosition(2, 3), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)),
                new ChessPieceAtPos(new ChessPosition(3, 5), new ChessPiece(ChessPieceType.Queen, ChessColor.Black, true)),
                new ChessPieceAtPos(new ChessPosition(2, 4), new ChessPiece(ChessPieceType.King, ChessColor.Black, true)),
                new ChessPieceAtPos(new ChessPosition(7, 1), new ChessPiece(ChessPieceType.Rook, ChessColor.Black, true)),
            };

            board     = new ChessBoard(pieces);
            enemyDraw = new ChessDraw(board, new ChessPosition(3, 5), new ChessPosition(2, 5));
            board     = board.ApplyDraw(enemyDraw);
            Assert.True(ChessDrawSimulator.Instance.GetCheckGameStatus(board, enemyDraw) == ChessGameStatus.Stalemate);
        }
Esempio n. 18
0
        private void testRochadeKingDraws()
        {
            // TODO: check if rochade attacks really work, seems not to be the case though because logic without attack validation passes the test

            // go through each king x rook combo
            for (int run = 0; run < 4; run++)
            {
                // get the (row, column) of the rook before rochade
                int rookRow = run / 2 == 0 ? 0 : 7;
                int rookCol = run % 2 == 0 ? 0 : 7;

                // determine the old and new positions of king / rook after rochade
                var oldKingPos = new ChessPosition(rookRow, 4);
                var newKingPos = new ChessPosition(rookRow, (rookCol == 0 ? 2 : 6));
                var oldRookPos = new ChessPosition(rookRow, rookCol);
                var newRookPos = new ChessPosition(rookRow, (rookCol == 0 ? 3 : 5));

                // determine the side performing a rochade
                var allyColor  = (rookRow == 0) ? ChessColor.White : ChessColor.Black;
                var enemyColor = allyColor.Opponent();

                // go through all 4 tuples bool x bool; only (false, false) should enable a rochade
                for (int wasMovedValue = 0; wasMovedValue < 4; wasMovedValue++)
                {
                    // determine whether king / rook was already moved before the rochade
                    bool wasKingMoved = wasMovedValue / 2 == 0;
                    bool wasRookMoved = wasMovedValue % 2 == 0;

                    // attach with a rook and go through every scenario threatening the king's rochade passage
                    for (int attack = 0; attack < 4; attack++)
                    {
                        var enemyPos     = new ChessPosition(4, (rookCol == 0) ? (4 - attack) : (4 + attack));
                        var enemyKingPos = new ChessPosition(4, 0);

                        for (int block = 0; block < 2; block++)
                        {
                            bool isBlocked = block == 1;
                            var  blockPos  = new ChessPosition(rookRow, 1);

                            var pieces = new List <ChessPieceAtPos>()
                            {
                                new ChessPieceAtPos(oldKingPos, new ChessPiece(ChessPieceType.King, allyColor, wasKingMoved)),
                                new ChessPieceAtPos(oldRookPos, new ChessPiece(ChessPieceType.Rook, allyColor, wasRookMoved)),
                                new ChessPieceAtPos(enemyPos, new ChessPiece(ChessPieceType.Rook, enemyColor, true)),
                                new ChessPieceAtPos(enemyKingPos, new ChessPiece(ChessPieceType.King, enemyColor, true)),
                            };

                            if (isBlocked)
                            {
                                pieces.Add(new ChessPieceAtPos(blockPos, new ChessPiece(ChessPieceType.Knight, allyColor, false)));
                            }

                            // init chess board and rochade draw
                            IChessBoard board = new ChessBitboard(new ChessBoard(pieces));
                            var         draw  = new ChessDraw(board, pieces[0].Position, newKingPos);

                            // check whether the draw validation returns the expected value
                            bool shouldRochadeBeValid = !wasKingMoved && !wasRookMoved && attack >= 3 && (!isBlocked || rookCol != 0);
                            bool isRochadeValid       = draw.IsValid(board);

                            Assert.True(shouldRochadeBeValid == isRochadeValid);

                            // check whether the rochade is applied correctly to the chess board
                            if (isRochadeValid)
                            {
                                board = board.ApplyDraw(draw);
                                Assert.True(
                                    !board.IsCapturedAt(oldKingPos) && board.GetPieceAt(newKingPos).Type == ChessPieceType.King && board.GetPieceAt(newKingPos).Color == allyColor &&
                                    !board.IsCapturedAt(oldRookPos) && board.GetPieceAt(newRookPos).Type == ChessPieceType.Rook && board.GetPieceAt(newRookPos).Color == allyColor
                                    );
                            }
                        }
                    }
                }
            }
        }