public void GeneratingAMazeWithABlockInTheMiddleWorks()
        {
            var map = new BitArreintjeFastInnerMap(128, 128);

            for (int y = 33; y < 96; y++)
            {
                for (int x = 33; x < 96; x++)
                {
                    map[x, y] = true;
                }
            }

            var mapFactory    = new InnerMapFactoryCustom <BitArreintjeFastInnerMap>(map);
            var randomFactory = new RandomFactory <NetRandom>(1337);

            var algorithm    = new AlgorithmBacktrack();
            var generatedMap = algorithm.GoGenerate(mapFactory, randomFactory, null);

            var path = PathFinderDepthFirstSmartWithPos.GoFind(map, null);

            using (var fs = new FileStream("GeneratingAMazeWithABlockInTheMiddleWorks.png", FileMode.Create))
            {
                WithPath.SaveMazeAsImageDeluxePng(map, path, fs);
            }
        }
        private static void FillInPathForRectangleX(Rectangle visibleRectangle, BitArreintjeFastInnerMap pathMap, MazePointClassLinkedList mazePointToWriteFor, MazePointClassLinkedList splitPos, RectangleWithPath rect1)
        {
            var theY = rect1.Y + 1 - visibleRectangle.Y;

            if (theY >= 0 && theY < visibleRectangle.Height)
            {
                var startXWriting = mazePointToWriteFor.X - visibleRectangle.X;
                var endWritingX   = splitPos.X - visibleRectangle.X;

                var lowest  = Math.Min(startXWriting, endWritingX);
                var highest = Math.Max(startXWriting, endWritingX);

                lowest  = Math.Max(lowest, 0);
                highest = Math.Min(highest, visibleRectangle.Width - 1);


                for (int i = lowest; i <= highest; i++)
                {
                    pathMap[i, theY] = true;
                }
            }
        }
        private static void FillInPathForRectangleY(Rectangle visibleRectangle, BitArreintjeFastInnerMap pathMap, MazePointClassLinkedList mazePointToWriteFor, MazePointClassLinkedList splitPos, RectangleWithPath rect1)
        {
            var theX = rect1.X + 1 - visibleRectangle.X;

            if (theX >= 0 && theX < visibleRectangle.Width)
            {
                var startYWriting = mazePointToWriteFor.Y - visibleRectangle.Y;
                var endWritingY   = splitPos.Y - visibleRectangle.Y;

                var lowest  = Math.Min(startYWriting, endWritingY);
                var highest = Math.Max(startYWriting, endWritingY);

                lowest  = Math.Max(lowest, 0);
                highest = Math.Min(highest, visibleRectangle.Height - 1);


                for (int i = lowest; i <= highest; i++)
                {
                    pathMap[theX, i] = true;
                }
            }
        }
        /// <summary>
        /// Finds the path between the start and the endpoint in a maze
        /// </summary>
        /// <param name="start">The start point</param>
        /// <param name="end">The end point</param>
        /// <param name="map">The maze.InnerMap</param>
        /// <param name="callBack">The callback that can be used to see what the pathfinder is doing (or null), the boolean true = a new path find thingy or false when it determined that path is not correct</param>
        /// <returns>The shortest path in a list of points</returns>
        public static List <MazePoint> GoFind(MazePoint start, MazePoint end, InnerMap map, Action <int, int, Boolean> callBack)
        {
            if (callBack == null)
            {
                callBack = (x, y, z) => { };
            }


            //Callback won't work nice with this since it will find its path from back to front
            //Swap them so we don't have to reverse at the end ;)
            //MazePoint temp = start;
            //start = end;
            //end = temp;



            int width  = map.Width;
            int height = map.Height;

            List <MazePoint> pointlist = new List <MazePoint>();


            //@todo Controleer dit
            InnerMap visited = new BitArreintjeFastInnerMap(width, height);

            for (int x = 0; x < width; x++)
            {
                //visited[x] = new BitArreintjeFast(height);
                for (int y = 0; y < height; y++)
                {
                    if (x == 0 || y == 0 || x == width || y == height)
                    {
                        visited[x, y] = true;
                    }
                    //else
                    //{
                    //    visited[x][y] = false;
                    //}
                }
            }


            //Hier begint het gedoe
            Stack <MazePoint> stackje = new Stack <MazePoint>();

            stackje.Push(start);
            visited[start.X, start.Y] = true;
            callBack.Invoke(start.X, start.Y, true);
            //form.pixelDraw(x, y, Brushes.White);
            while (stackje.Count != 0)
            {
                MazePoint cur = stackje.Peek();
                int       x   = cur.X;
                int       y   = cur.Y;

                if (end.X == x && end.Y == y)
                {
                    callBack.Invoke(x, y, true);
                    break;
                }

                MazePoint target = new MazePoint(-1, -1);
                if (x + 1 < width - 1 && !visited[x + 1, y] && map[x + 1, y])
                {
                    target = new MazePoint(x + 1, y);
                }
                else if (y + 1 < height - 1 && !visited[x, y + 1] && map[x, y + 1])
                {
                    target = new MazePoint(x, y + 1);
                }
                else if (x - 1 > 0 && !visited[x - 1, y] && map[x - 1, y])
                {
                    target = new MazePoint(x - 1, y);
                }
                else if (y - 1 > 0 && !visited[x, y - 1] && map[x, y - 1])
                {
                    target = new MazePoint(x, y - 1);
                }

                //Thread.Sleep(1000);

                if (target.X != -1)
                {
                    callBack.Invoke(x, y, true);
                    //var target = targets[r.Next(targets.Count)];
                    stackje.Push(target);
                    visited[target.X, target.Y] = true;
                    //form.pixelDraw(target.X, target.Y, Brushes.Blue);
                    //Thread.Sleep(200);

                    //if (target.X < x)
                    //{
                    //    visited[x - 1][y] = true;
                    //    //form.pixelDraw(x - 1, y, Brushes.White);
                    //}
                    //else if (target.X > x)
                    //{
                    //    visited[x + 1][y] = true;
                    //    //form.pixelDraw(x + 1, y, Brushes.White);
                    //}
                    //else if (target.Y < y)
                    //{
                    //    visited[x][y - 1] = true;
                    //    //form.pixelDraw(x, y - 1, Brushes.White);
                    //}
                    //else if (target.Y > y)
                    //{
                    //    visited[x][y + 1] = true;
                    //    //form.pixelDraw(x, y + 1, Brushes.White);
                    //}
                }
                else
                {
                    callBack.Invoke(x, y, false);
                    stackje.Pop();
                }
            }

            pointlist.AddRange(stackje);

            pointlist.Reverse();

            return(pointlist);
        }
Example #5
0
        public InnerMap GenerateMapPart(int xStart, int yStart, int widthPart, int heightPart)
        {
            InnerMap map = new BitArreintjeFastInnerMap(widthPart, heightPart);

            //If the maze is out of screen
            var theRightEdge  = Math.Max(((xStart + widthPart) - width), 0);
            var theBottomEdge = Math.Max(((yStart + heightPart) - height), 0);

            map.FillMap(true);

            //Add walls
            if (xStart == 0)
            {
                for (int y = 0; y < heightPart - theBottomEdge; y++)
                {
                    map[0, y] = false;
                }
            }

            if (yStart == 0)
            {
                for (int x = 0; x < widthPart - theRightEdge; x++)
                {
                    map[x, 0] = false;
                }
            }

            if (xStart + widthPart >= width)
            {
                for (int y = 0; y < heightPart - theBottomEdge; y++)
                {
                    map[widthPart - 1 - theRightEdge, y] = false;
                }

                if (UnevenHelper.NumberIsEven(width))
                {
                    for (int y = 0; y < heightPart - theBottomEdge; y++)
                    {
                        map[widthPart - 2 - theRightEdge, y] = false;
                    }
                }
            }

            if (yStart + heightPart >= height)
            {
                for (int x = 0; x < widthPart - theRightEdge; x++)
                {
                    map[x, heightPart - 1 - theBottomEdge] = false;
                }

                if (UnevenHelper.NumberIsEven(height))
                {
                    for (int x = 0; x < widthPart - theRightEdge; x++)
                    {
                        map[x, heightPart - 2 - theBottomEdge] = false;
                    }
                }
            }


            var visibleRectangle = new Rectangle(xStart, yStart, widthPart, heightPart, 0);

            var rectangles = new Stack <Rectangle>();

            var random = new NetRandom(seed);

            var startRect = new Rectangle(0, 0, UnevenHelper.MakeUneven(width), UnevenHelper.MakeUneven(height), random.Next());

            rectangles.Push(startRect);


            while (rectangles.Count > 0)
            {
                var curRect = rectangles.Pop();

                //Console.WriteLine($"X: {curRect.X} Y: {curRect.Y} Width: {curRect.Width} Height: {curRect.Height}");

                random.Reinitialise(curRect.Seed);

                bool horizontalSplit = true;
                //form.drawRectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height, Brushes.Pink);

                if (curRect.Width > curRect.Height)
                {
                    horizontalSplit = false;
                }
                else if (curRect.Width < curRect.Height)
                {
                    horizontalSplit = true;
                }
                else
                {
                    if (random.Next(2) == 0)
                    {
                        horizontalSplit = false;
                    }
                }

                if (horizontalSplit)
                {
                    int splitnumber = 2 + random.Next((curRect.Height - 2) / 2) * 2;
                    int opening     = 1 + random.Next((curRect.Width) / 2) * 2 + curRect.X;

                    Rectangle rect1 = new Rectangle(curRect.X, curRect.Y, curRect.Width, splitnumber + 1, random.Next());
                    Rectangle rect2 = new Rectangle(curRect.X, curRect.Y + splitnumber, curRect.Width, curRect.Height - splitnumber, random.Next());


                    int xStartDraw = Math.Max(0, curRect.X - xStart);
                    int xEndDraw   = Math.Min(widthPart, curRect.X - xStart + curRect.Width);

                    int yPos = curRect.Y + splitnumber - yStart;

                    if (yPos >= 0 && yPos < heightPart - 1)
                    {
                        for (int i = xStartDraw; i < xEndDraw; i++)
                        {
                            if (i != opening - xStart)
                            {
                                map[i, yPos] = false;
                            }
                        }
                    }

                    if (IsValidRect(visibleRectangle, rect1))
                    {
                        rectangles.Push(rect1);
                    }
                    if (IsValidRect(visibleRectangle, rect2))
                    {
                        rectangles.Push(rect2);
                    }
                }
                else
                {
                    int splitnumber = 2 + random.Next((curRect.Width - 2) / 2) * 2;
                    int opening     = 1 + random.Next((curRect.Height) / 2) * 2 + curRect.Y;

                    Rectangle rect1 = new Rectangle(curRect.X, curRect.Y, splitnumber + 1, curRect.Height, random.Next());
                    Rectangle rect2 = new Rectangle(curRect.X + splitnumber, curRect.Y, curRect.Width - splitnumber, curRect.Height, random.Next());


                    var yStartDraw = Math.Max(0, curRect.Y - yStart);
                    int yEndDraw   = Math.Min(heightPart, curRect.Y - yStart + curRect.Height);

                    int xPos = curRect.X + splitnumber - xStart;

                    if (xPos >= 0 && xPos < widthPart - 1)
                    {
                        for (int i = yStartDraw; i < yEndDraw; i++)
                        {
                            if (i != opening - yStart)
                            {
                                map[xPos, i] = false;
                            }
                        }
                    }


                    if (IsValidRect(visibleRectangle, rect1))
                    {
                        rectangles.Push(rect1);
                    }
                    if (IsValidRect(visibleRectangle, rect2))
                    {
                        rectangles.Push(rect2);
                    }
                }
            }

            return(map);
        }
Example #6
0
        /// <summary>
        /// This method performs a preanalysis on the path to make sure there's no super high memory usage for a certain area
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="pathPosjes"></param>
        /// <param name="lineSavingProgress"></param>
        /// <param name="debugMessageCallback"></param>
        private void SaveMazeAsImageDeluxePngWithDynamicallyGeneratedPathWithAnalysis(string fileName, IEnumerable <MazePointPos> pathPosjes, Action <int, int> lineSavingProgress, Action <string> debugMessageCallback = null)
        {
            if (debugMessageCallback == null)
            {
                debugMessageCallback = (x) => { };
            }

            debugMessageCallback("Performing path analysis...");

            var  pathPointsPerRow = new int[this.Height];
            long totalPathLength  = 0;

            for (int i = 0; i < this.Height; i++)
            {
                pathPointsPerRow[i] = 0;
            }

            foreach (var pathPos in pathPosjes)
            {
                pathPointsPerRow[pathPos.Y]++;
                totalPathLength++;
            }

            debugMessageCallback(string.Format("Path analysis completed. Total path length: {0}, this would take up {1}mb.", totalPathLength, Math.Round(totalPathLength * 9.0 / 1024.0 / 1024.0, 2)));

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var compinfo   = new Microsoft.VisualBasic.Devices.ComputerInfo();
            var memoryFree = compinfo.AvailablePhysicalMemory;

            debugMessageCallback(string.Format("Memory free: {0}mb", memoryFree / 1024 / 1024));
            memoryFree = (ulong)(memoryFree * 0.6);
            debugMessageCallback(string.Format("Setting max usage to 60% of this: {0}mb", memoryFree / 1024 / 1024));

            debugMessageCallback("Determining desired rows to generate each path cycle...");
            int rowsPerPathDeterminingCycle = FindTheMinimalRowsToWriteForPng(debugMessageCallback, pathPointsPerRow, memoryFree);



            int tiffTileSize = HybridInnerMap.GridSize;

            if (rowsPerPathDeterminingCycle < tiffTileSize)
            {
                debugMessageCallback(string.Format("We can't work with the default tilesize of '{0}' so we have to scale it back to RowsPerCycle: '{1}'", tiffTileSize, rowsPerPathDeterminingCycle));
                tiffTileSize = rowsPerPathDeterminingCycle;
            }

            debugMessageCallback(string.Format("TiffTileSize: {0}", tiffTileSize));

            debugMessageCallback("Starting generation of Maze Path and saving maze...");

            //Should actually be Width -1 -1 but since we use the full Width it's only once -1
            //This will count the amount of tiles per line so if it's 15 Pixels we still want 2 tiles of 8
            int tilesInWidth = (((this.Width - 1) / tiffTileSize) + 1);



            ImageInfo imi = new ImageInfo(this.Width - 1, this.Height - 1, 8, false); // 8 bits per channel, no alpha
            // open image for writing
            PngWriter png = CreatePngWriter(fileName, imi);

            // add some optional metadata (chunks)
            png.GetMetadata().SetDpi(100.0);
            png.GetMetadata().SetTimeNow(0); // 0 seconds fron now = now
            png.CompLevel = 4;
            //png.GetMetadata().SetText(PngChunkTextVar.KEY_Title, "Just a text image");
            //PngChunk chunk = png.GetMetadata().SetText("my key", "my text .. bla bla");
            //chunk.Priority = true; // this chunk will be written as soon as possible



            //int stepsPerLoop = rowsPerPathDeterminingCycle;

            int partNumber = 0;

            int yChunkStart = 0;

            while (yChunkStart < this.Height - 1)
            {
                //We must use rowsperpathdeterminingcycle here instead of tifftilesize because else you might get into a scenario where the first 4 values and the second 4 values are beneath 1000. But if we would take value 2 to 6 which are also 4 values we would go above 1000.
                //And yes I thought about this pretty well, it needs to be like this because you get forced into reading 500 lines of path from for example 1000 to 1500 where the other thing is 2000, hmmmm...
                //Or not I really need to think about this a bit more. Because if the chunk size is 1000 then you can never end up reading something smaller then that which works because the rowsperpath is always bigger.
                //So yeah, because rows per path is always a multiple or equal to tifftilesize you can never go out of sync becuase no matter what happens, e.g. tifftile = 500 and perpath = 2000. When you're at 2500 you just need to read 500. And you are never forced in reading anything that was
                //not measured. Because you can't end up in having to read somewhere from 1250 to 1750 because of the multiple thingy. Ok I'm quite sure now it needs to be tiffTileSize.
                //
                //Additional note, it always needs to be a multiple of tiffTileSize because we write tiles at a time (we can't write half tiles). So that's why we don't want some stupidly small numbers here.
                int stepsThisLoop = FindTheMaxPathRowsThatWouldFitInMemoryFromHerePng(debugMessageCallback, pathPointsPerRow, yChunkStart, tiffTileSize, memoryFree);

                var yChunkEnd = Math.Min(yChunkStart + stepsThisLoop, this.Height - 1);
                stepsThisLoop = yChunkEnd - yChunkStart;

                var wObtainPathPart = Stopwatch.StartNew();

                //We don't use a ToList here because we do actually know the expected list size beforehand. This way we make sure we don't have to do any internal Array Resizing.
                var expectedPathCount   = pathPointsPerRow.Skip(yChunkStart).Take(yChunkEnd - yChunkStart).Sum();
                var pathPointsHere      = new List <MazePointPos>(expectedPathCount);
                int currentPathPosPoint = 0;
                foreach (var pathPos in pathPosjes.Where(t => t.Y >= yChunkStart && t.Y < yChunkEnd))
                {
                    pathPointsHere.Add(pathPos);
                    currentPathPosPoint++;
                }
                wObtainPathPart.Stop();

                if (pathPointsHere.Count != expectedPathCount)
                {
                    debugMessageCallback(string.Format("Warning: Something strange is happening where the actual path point count '{0}' is not equal to the expected path point count '{1}' (Maze will still save correctly but it uses more memory then expected)", pathPointsHere.Count, expectedPathCount));
                }

                var wSort = Stopwatch.StartNew();
                pathPointsHere.Sort((first, second) =>
                {
                    if (first.Y == second.Y)
                    {
                        return(first.X - second.X);
                    }
                    return(first.Y - second.Y);
                });
                wSort.Stop();



                var wGmemorifiedPieceOpMap = Stopwatch.StartNew();

                var innerMapTemporaryInMemoryCopy = new BitArreintjeFastInnerMap(this.Width, stepsThisLoop);



                for (int startY = yChunkStart; startY < yChunkEnd; startY += tiffTileSize)
                {
                    for (int startX = 0; startX < this.Width - 1; startX += tiffTileSize)
                    {
                        int yStart = startY - yChunkStart;
                        int yEnd   = yStart + tiffTileSize;

                        for (int y = startY, othery = yStart; othery < yEnd; y++, othery++)
                        {
                            for (int x = startX, otherx = 0; otherx < tiffTileSize; x++, otherx++)
                            {
                                innerMapTemporaryInMemoryCopy[x, othery] = innerMap[x, y];
                            }
                        }
                    }
                }



                wGmemorifiedPieceOpMap.Stop();



                int curpos = 0;

                var wSaveAsImage = Stopwatch.StartNew();

                var yChunkMaxRealEnzo = Math.Min(yChunkEnd, this.Height - 1);

                for (int startY = yChunkStart, y = 0; startY < yChunkMaxRealEnzo; startY += 1, y++)
                {
                    ImageLine iline = new ImageLine(imi);

                    //int xMax = Math.Min(this.Width - 1 - startX, tiffTileSize);
                    int yMax = Math.Min(this.Height - 1 - startY, tiffTileSize);
                    for (int x = 0, otherx = 0; otherx < this.Width - 1; x++, otherx++)
                    {
                        byte r = 0;
                        byte g = 0;
                        byte b = 0;

                        MazePointPos curPathPos;
                        if (curpos < pathPointsHere.Count)
                        {
                            curPathPos = pathPointsHere[curpos];
                            if (curPathPos.X == x && curPathPos.Y == startY)
                            {
                                r = curPathPos.RelativePos;
                                g = (byte)(255 - curPathPos.RelativePos);
                                b = 0;
                                curpos++;
                            }
                            else if (innerMapTemporaryInMemoryCopy[x, y])
                            {
                                r = 255;
                                g = 255;
                                b = 255;
                            }
                        }
                        else if (innerMapTemporaryInMemoryCopy[x, y])
                        {
                            r = 255;
                            g = 255;
                            b = 255;
                        }



                        ImageLineHelper.SetPixel(iline, x, r, g, b);
                    }



                    //var result = tif.WriteEncodedTile(tileNumber, color_ptr, tiffTileSize * tiffTileSize * 3);
                    //var result = tif.WriteTile(color_ptr, startX / tileSize, startY / tileSize, 0, 0);
                    //var result = tif.WriteRawTile(tileNumber, color_ptr, tileSize * tileSize * 3);
                    //Result should not be -1

                    //lineSavingProgress((int)Math.Min((tileNumber + 1L) * tiffTileSize / tilesInWidth, this.Height - 2), this.Height - 2);
                    png.WriteRow(iline, y + yChunkStart);
                    lineSavingProgress(y + yChunkStart, this.Height - 2);
                }



                wSaveAsImage.Stop();

                debugMessageCallback(string.Format("{0}: YChunkStart: {1}, YChunkEnd: {2}, Rows written: {3}, Count: {4}, Time to generate this part: {5} sec, Time to sort this part: {6} sec, Time to put this part in memory: {7}, Time to save this part in the image: {8} sec, Combined time: {9} sec, Size: {10}mb",
                                                   partNumber,
                                                   yChunkStart,
                                                   yChunkEnd,
                                                   stepsThisLoop,
                                                   pathPointsHere.Count,
                                                   Math.Round(wObtainPathPart.Elapsed.TotalSeconds, 2),
                                                   Math.Round(wSort.Elapsed.TotalSeconds, 2),
                                                   Math.Round(wGmemorifiedPieceOpMap.Elapsed.TotalSeconds, 2),
                                                   Math.Round(wSaveAsImage.Elapsed.TotalSeconds, 2),
                                                   Math.Round(wObtainPathPart.Elapsed.TotalSeconds + wSort.Elapsed.TotalSeconds + wGmemorifiedPieceOpMap.Elapsed.TotalSeconds + wSaveAsImage.Elapsed.TotalSeconds, 2),
                                                   Math.Round(pathPointsHere.Count * 9.0 / 1024.0 / 1024.0, 3)));
                partNumber++;

                yChunkStart += stepsThisLoop;

                //Do some forced garbage collection since we're finished with this loop
                pathPointsHere = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
            }

            png.End();

            //    tif.FlushData();
            //}
        }
        public InnerMap GenerateMapPartWithPath(int xStart, int yStart, int width, int height, int widthPart, int heightPart, IRandomFactory randomFactory)
        {
            var visibleRectangle = new Rectangle(xStart, yStart, widthPart, heightPart, 0);
            //Console.WriteLine($"Generating rectangle: {visibleRectangle}");

            var random = randomFactory.Create();

            InnerMap map = new BitArreintjeFastInnerMap(widthPart, heightPart)
            {
                StartX = xStart, StartY = yStart
            };

            //If the maze is out of screen
            var theRightEdge  = Math.Max(((xStart + widthPart) - width), 0);
            var theBottomEdge = Math.Max(((yStart + heightPart) - height), 0);

            map.FillMap(true);

            var pathMap = new BitArreintjeFastInnerMap(widthPart, heightPart)
            {
                StartX = xStart, StartY = yStart
            };

            //Add walls
            if (xStart == 0)
            {
                for (int y = 0; y < heightPart - theBottomEdge; y++)
                {
                    map[0, y] = false;
                }
            }

            if (yStart == 0)
            {
                for (int x = 0; x < widthPart - theRightEdge; x++)
                {
                    map[x, 0] = false;
                }
            }

            if (xStart + widthPart >= width)
            {
                for (int y = 0; y < heightPart - theBottomEdge; y++)
                {
                    map[widthPart - 1 - theRightEdge, y] = false;
                }

                if (UnevenHelper.NumberIsEven(width))
                {
                    for (int y = 0; y < heightPart - theBottomEdge; y++)
                    {
                        map[widthPart - 2 - theRightEdge, y] = false;
                    }
                }
            }

            if (yStart + heightPart >= height)
            {
                for (int x = 0; x < widthPart - theRightEdge; x++)
                {
                    map[x, heightPart - 1 - theBottomEdge] = false;
                }

                if (UnevenHelper.NumberIsEven(height))
                {
                    for (int x = 0; x < widthPart - theRightEdge; x++)
                    {
                        map[x, heightPart - 2 - theBottomEdge] = false;
                    }
                }
            }

            var rectangles = new Stack <RectangleWithPath>();


            var startRect = new RectangleWithPath(0, 0, UnevenHelper.MakeUneven(width), UnevenHelper.MakeUneven(height), random.Next(), new MazePointClassLinkedList(1, 1), new MazePointClassLinkedList(width - 3, height - 3), true);

            rectangles.Push(startRect);

            while (rectangles.Count > 0)
            {
                var curRect = rectangles.Pop();

                //Console.WriteLine($"X: {curRect.X} Y: {curRect.Y} Width: {curRect.Width} Height: {curRect.Height}");

                random.Reinitialise(curRect.Seed);

                bool horizontalSplit = true;

                if (curRect.Width > curRect.Height)
                {
                    horizontalSplit = false;
                }
                else if (curRect.Width < curRect.Height)
                {
                    horizontalSplit = true;
                }
                else
                {
                    if (random.Next(2) == 0)
                    {
                        horizontalSplit = false;
                    }
                }

                if (horizontalSplit)
                {
                    int splitnumber = 2 + random.Next((curRect.Height - 2) / 2) * 2;
                    int opening     = 1 + random.Next((curRect.Width) / 2) * 2 + curRect.X;

                    var splitPos = new MazePointClassLinkedList(opening, curRect.Y + splitnumber);

                    var rect1 = new RectangleWithPath(curRect.X, curRect.Y, curRect.Width, splitnumber + 1, random.Next());
                    var rect2 = new RectangleWithPath(curRect.X, curRect.Y + splitnumber, curRect.Width, curRect.Height - splitnumber, random.Next());

                    if (curRect.PathPassesThroughThis)
                    {
                        var pathPassesThroughOpening = AreNumberOnTheSidesOfThisValue(splitPos.Y, curRect.MazePointLeft.Y, curRect.MazePointRight.Y);
                        DetermineRectanglePathPassingThrough(curRect, rect1, splitPos);
                        DetermineRectanglePathPassingThrough(curRect, rect2, splitPos);

                        if (pathPassesThroughOpening)
                        {
                            splitPos.InsertMeInBetweenTheseTwo(curRect.MazePointLeft, curRect.MazePointRight);
                            if (visibleRectangle.IntersectsWith(splitPos))
                            {
                                pathMap[splitPos.X - visibleRectangle.X, splitPos.Y - visibleRectangle.Y] = true;
                            }
                        }

                        //DrawRedStuff
                        if (rect1.PathPassesThroughThis && rect1.Height == 3)
                        {
                            FillInPathForRectangleX(visibleRectangle, pathMap, rect1.MazePointLeft, rect1.MazePointRight, rect1);
                        }

                        if (rect2.PathPassesThroughThis && rect2.Height == 3)
                        {
                            //FillInPathForRectangle(visibleRectangle, pathMap, curRect.MazePointRight.Previous, curRect.MazePointRight, rect2);
                            FillInPathForRectangleX(visibleRectangle, pathMap, rect2.MazePointLeft, rect2.MazePointRight, rect2);
                        }
                    }

                    int xStartDraw = Math.Max(0, curRect.X - xStart);
                    int xEndDraw   = Math.Min(widthPart, curRect.X - xStart + curRect.Width);

                    int yPos = curRect.Y + splitnumber - yStart;

                    if (yPos >= 0 && yPos < heightPart - 1)
                    {
                        for (int i = xStartDraw; i < xEndDraw; i++)
                        {
                            if (i != opening - xStart)
                            {
                                map[i, yPos] = false;
                            }
                        }
                    }

                    if (IsValidRect(visibleRectangle, rect1))
                    {
                        rectangles.Push(rect1);
                    }
                    if (IsValidRect(visibleRectangle, rect2))
                    {
                        rectangles.Push(rect2);
                    }
                }
                else
                {
                    int splitnumber = 2 + random.Next((curRect.Width - 2) / 2) * 2;
                    int opening     = 1 + random.Next((curRect.Height) / 2) * 2 + curRect.Y;

                    var splitPos = new MazePointClassLinkedList(curRect.X + splitnumber, opening);

                    var rect1 = new RectangleWithPath(curRect.X, curRect.Y, splitnumber + 1, curRect.Height, random.Next());
                    var rect2 = new RectangleWithPath(curRect.X + splitnumber, curRect.Y, curRect.Width - splitnumber, curRect.Height, random.Next());

                    if (curRect.PathPassesThroughThis)
                    {
                        var pathPassesThroughOpening = AreNumberOnTheSidesOfThisValue(splitPos.X, curRect.MazePointLeft.X, curRect.MazePointRight.X);
                        DetermineRectanglePathPassingThrough(curRect, rect1, splitPos);
                        DetermineRectanglePathPassingThrough(curRect, rect2, splitPos);

                        if (pathPassesThroughOpening)
                        {
                            splitPos.InsertMeInBetweenTheseTwo(curRect.MazePointLeft, curRect.MazePointRight);
                            if (visibleRectangle.IntersectsWith(splitPos))
                            {
                                pathMap[splitPos.X - visibleRectangle.X, splitPos.Y - visibleRectangle.Y] = true;
                            }
                        }

                        //DrawRedStuff
                        if (rect1.PathPassesThroughThis && rect1.Width == 3)
                        {
                            FillInPathForRectangleY(visibleRectangle, pathMap, rect1.MazePointLeft, rect1.MazePointRight, rect1);
                        }

                        if (rect2.PathPassesThroughThis && rect2.Width == 3)
                        {
                            //FillInPathForRectangle(visibleRectangle, pathMap, curRect.MazePointRight.Previous, curRect.MazePointRight, rect2);
                            FillInPathForRectangleY(visibleRectangle, pathMap, rect2.MazePointLeft, rect2.MazePointRight, rect2);
                        }
                    }

                    var yStartDraw = Math.Max(0, curRect.Y - yStart);
                    int yEndDraw   = Math.Min(heightPart, curRect.Y - yStart + curRect.Height);

                    int xPos = curRect.X + splitnumber - xStart;

                    if (xPos >= 0 && xPos < widthPart - 1)
                    {
                        for (int i = yStartDraw; i < yEndDraw; i++)
                        {
                            if (i != opening - yStart)
                            {
                                map[xPos, i] = false;
                            }
                        }
                    }

                    if (IsValidRect(visibleRectangle, rect1))
                    {
                        rectangles.Push(rect1);
                    }
                    if (IsValidRect(visibleRectangle, rect2))
                    {
                        rectangles.Push(rect2);
                    }
                }

                //using (var fs = new FileStream("DivisionDynamicWithPath2.png", FileMode.Create))
                //{
                //    WithPath.SaveMazeAsImageDeluxePng(map, pathMap, fs);
                //}
            }

            map.PathData = pathMap;
            return(map);
        }