Example #1
0
    private RoomDescriptionGrid2D GetStartEndRoomDescription()
    {
        var roomsTemplates = new List <RoomTemplateGrid2D>();
        var doors          = new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 2);

        System.Random rnd = new System.Random();

        var transformations = new List <TransformationGrid2D>()
        {
            TransformationGrid2D.Identity
        };


        var roomTemplate = new RoomTemplateGrid2D(
            PolygonGrid2D.GetRectangle(roomMinWidth, roomMinHeight),
            doors,
            allowedTransformations: transformations);

        roomsTemplates.Add(roomTemplate);


        var roomDescription = new RoomDescriptionGrid2D
                              (
            isCorridor: false,
            roomTemplates: roomsTemplates
                              );

        return(roomDescription);
    }
Example #2
0
        public static RoomTemplate ToOldRoomTemplate(this RoomTemplateGrid2D roomTemplate)
        {
            var       doorMode    = roomTemplate.Doors;
            IDoorMode oldDoorMode = null;

            if (roomTemplate.RepeatMode == null)
            {
                throw new NotSupportedException("Null repeat mode is currently not supported");
            }

            if (doorMode is SimpleDoorModeGrid2D simpleDoorMode)
            {
                if (simpleDoorMode.DoorSocket != null)
                {
                    throw new NotSupportedException("Old room templates support only null sockets");
                }

                oldDoorMode = new SimpleDoorMode(simpleDoorMode.DoorLength, simpleDoorMode.CornerDistance);
            }
            else if (doorMode is ManualDoorModeGrid2D manualDoorMode)
            {
                if (manualDoorMode.Doors.Any(x => x.Socket != null))
                {
                    throw new NotSupportedException("Old room templates support only null sockets");
                }

                oldDoorMode = new ManualDoorMode(manualDoorMode.Doors.Select(x => new OrthogonalLineGrid2D(x.From, x.To)).ToList());
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }

            return(new RoomTemplate(roomTemplate.Outline, oldDoorMode, roomTemplate.AllowedTransformations, roomTemplate.RepeatMode.Value, roomTemplate.Name));
        }
 public RoomTemplateInstanceGrid2D(RoomTemplateGrid2D roomTemplate, PolygonGrid2D roomShape, List <DoorLineGrid2D> doorLines, List <TransformationGrid2D> transformations)
 {
     RoomTemplate    = roomTemplate;
     RoomShape       = roomShape;
     DoorLines       = doorLines;
     Transformations = transformations;
 }
Example #4
0
    private RoomDescriptionGrid2D GetRoomDescription()
    {
        var roomsTemplates = new List <RoomTemplateGrid2D>();
        var doors          = new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 2);

        System.Random rnd             = new System.Random();
        var           roomWidthArray  = Enumerable.Range(roomMinWidth, roomMaxWidth - roomMinWidth + 1).ToArray();
        var           roomHieghtArray = Enumerable.Range(roomMinHeight, roomMaxHeight - roomMinHeight + 1).ToArray();

        var transformations = new List <TransformationGrid2D>()
        {
            TransformationGrid2D.Identity
        };

        for (var i = 0; i <= numberOfRooms; i++)
        {
            var roomTemplate = new RoomTemplateGrid2D(
                PolygonGrid2D.GetRectangle(roomWidthArray.OrderBy(a => UnityEngine.Random.value).FirstOrDefault(), roomHieghtArray.OrderBy(a => UnityEngine.Random.value).FirstOrDefault()),
                doors,
                allowedTransformations: transformations);

            roomsTemplates.Add(roomTemplate);
        }

        var roomDescription = new RoomDescriptionGrid2D
                              (
            isCorridor: false,
            roomTemplates: roomsTemplates
                              );

        return(roomDescription);
    }
Example #5
0
        public static List <RoomTemplateGrid2D> GetNewCorridorRoomTemplates(List <int> offsets, int width = 1)
        {
            if (offsets == null)
            {
                return(null);
            }

            var roomTemplates   = new List <RoomTemplateGrid2D>();
            var transformations = TransformationGrid2DHelper.GetAllTransformationsOld().ToList();

            foreach (var offset in offsets)
            {
                var length       = offset;
                var roomTemplate = new RoomTemplateGrid2D(
                    PolygonGrid2D.GetRectangle(length, width),
                    new ManualDoorModeGrid2D(new List <DoorGrid2D>()
                {
                    new DoorGrid2D(new Vector2Int(0, 0), new Vector2Int(0, width)),
                    new DoorGrid2D(new Vector2Int(length, 0), new Vector2Int(length, width)),
                }),
                    allowedTransformations: transformations,
                    repeatMode: RoomTemplateRepeatMode.AllowRepeat
                    );

                roomTemplates.Add(roomTemplate);
            }

            return(roomTemplates);
        }
Example #6
0
        /// <summary>
        ///     Computes a room room template from a given room template game object.
        /// </summary>
        /// <param name="roomTemplatePrefab"></param>
        /// <param name="allowedTransformations"></param>
        /// <returns></returns>
        public static RoomTemplateGrid2D GetRoomTemplate(GameObject roomTemplatePrefab, List <TransformationGrid2D> allowedTransformations = null)
        {
            if (allowedTransformations == null)
            {
                allowedTransformations = new List <TransformationGrid2D> {
                    TransformationGrid2D.Identity
                };
            }

            var polygon = GetPolygonFromRoomTemplate(roomTemplatePrefab);

            var doors = roomTemplatePrefab.GetComponent <Doors>();

            if (doors == null)
            {
                throw new GeneratorException($"Room template \"{roomTemplatePrefab.name}\" does not have any doors assigned.");
            }

            var roomTemplateComponent = roomTemplatePrefab.GetComponent <RoomTemplateSettings>();
            var repeatMode            = roomTemplateComponent?.RepeatMode ?? RoomTemplateRepeatMode.AllowRepeat;
            var doorMode = doors.GetDoorMode();

            var roomDescription = new RoomTemplateGrid2D(polygon, doorMode, roomTemplatePrefab.name, repeatMode, allowedTransformations);

            return(roomDescription);
        }
Example #7
0
        public void Run()
        {
            // Create square room template
            var squareRoomTemplate = new RoomTemplateGrid2D(
                PolygonGrid2D.GetSquare(8),
                new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 1)
                );

            // Create rectangle room template
            var rectangleRoomTemplate = new RoomTemplateGrid2D(
                PolygonGrid2D.GetRectangle(6, 10),
                new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 1)
                );

            // Create a room description which says that the room is not a corridor and that it can use the two room templates
            var roomDescription = new RoomDescriptionGrid2D(
                isCorridor: false,
                roomTemplates: new List <RoomTemplateGrid2D>()
            {
                squareRoomTemplate, rectangleRoomTemplate
            }
                );

            // Create an instance of the level description
            var levelDescription = new LevelDescriptionGrid2D <int>();

            // Add 4 rooms to the level, use the room description that we created beforehand
            levelDescription.AddRoom(0, roomDescription);
            levelDescription.AddRoom(1, roomDescription);
            levelDescription.AddRoom(2, roomDescription);
            levelDescription.AddRoom(3, roomDescription);

            // Add connections between the rooms - the level graph will be a cycle with 4 vertices
            levelDescription.AddConnection(0, 1);
            levelDescription.AddConnection(0, 3);
            levelDescription.AddConnection(1, 2);
            levelDescription.AddConnection(2, 3);

            // Create an instance of the generate and generate a layout
            var generator = new GraphBasedGeneratorGrid2D <int>(levelDescription);
            var layout    = generator.GenerateLayout();

            // Export the resulting layout as PNG
            var drawer = new DungeonDrawer <int>();

            drawer.DrawLayoutAndSave(layout, "simple_layout.png", new DungeonDrawerOptions()
            {
                Width  = 2000,
                Height = 2000,
            });

            var layout2 = generator.GenerateLayout();

            // Export the resulting layout as PNG
            drawer.DrawLayoutAndSave(layout, "simple_layout_2.png", new DungeonDrawerOptions()
            {
                Width  = 2000,
                Height = 2000,
            });
        }
Example #8
0
        /// <summary>
        ///     Computes a room room template from a given room template game object.
        /// </summary>
        /// <param name="roomTemplatePrefab"></param>
        /// <param name="roomTemplate"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool TryGetRoomTemplate(GameObject roomTemplatePrefab, out RoomTemplateGrid2D roomTemplate, out ActionResult result)
        {
            roomTemplate = null;

            // Check that the room template has all the required components
            var requiredComponentsResult = RoomTemplateDiagnostics.CheckComponents(roomTemplatePrefab);

            if (requiredComponentsResult.HasErrors)
            {
                result = requiredComponentsResult;
                return(false);
            }

            PolygonGrid2D polygon = null;

            // TODO: improve
            try
            {
                polygon = GetPolygonFromRoomTemplate(roomTemplatePrefab);
            }
            catch (ArgumentException)
            {
                /* empty */
            }

            // Check that the outline of the room template is valid
            if (polygon == null)
            {
                result = new ActionResult();
                result.AddError("The outline of the room template is not valid. Please consult the documentation.");
                return(false);
            }

            var allowedTransformations = new List <TransformationGrid2D> {
                TransformationGrid2D.Identity
            };
            var roomTemplateComponent = roomTemplatePrefab.GetComponent <RoomTemplateSettings>();
            var repeatMode            = roomTemplateComponent?.RepeatMode ?? RoomTemplateRepeatMode.AllowRepeat;
            var doors    = roomTemplatePrefab.GetComponent <Doors>();
            var doorMode = doors.GetDoorMode();

            // Check that the doors are valid
            var doorsCheck = RoomTemplateDiagnostics.CheckDoors(polygon, doorMode);

            if (doorsCheck.HasErrors)
            {
                result = doorsCheck;
                return(false);
            }

            roomTemplate = new RoomTemplateGrid2D(polygon, doorMode, roomTemplatePrefab.name, repeatMode, allowedTransformations);

            result = new ActionResult();
            return(true);
        }
Example #9
0
        private static RoomTemplate GetOldRoomTemplate(RoomTemplateGrid2D roomTemplate, Dictionary <RoomTemplateGrid2D, RoomTemplate> mapping)
        {
            if (mapping.TryGetValue(roomTemplate, out var cached))
            {
                return(cached);
            }

            var oldRoomTemplate = roomTemplate.ToOldRoomTemplate();

            mapping[roomTemplate] = oldRoomTemplate;

            return(oldRoomTemplate);
        }
        private HashSet <int> GetDoorLengths(RoomTemplateGrid2D roomTemplate)
        {
            var doorMode    = roomTemplate.Doors;
            var doors       = doorMode.GetDoors(roomTemplate.Outline);
            var doorLengths = new HashSet <int>();

            foreach (var door in doors)
            {
                doorLengths.Add(door.Length + 1);
            }

            return(doorLengths);
        }
Example #11
0
    private RoomDescriptionGrid2D GetCorridorDescription()
    {
        var corridorOutline = PolygonGrid2D.GetRectangle(4, 3);
        var corridorDoors   = new ManualDoorModeGrid2D(new List <DoorGrid2D>()
        {
            new DoorGrid2D(new Edgar.Geometry.Vector2Int(0, 1), new Edgar.Geometry.Vector2Int(0, 2)),
            new DoorGrid2D(new Edgar.Geometry.Vector2Int(4, 1), new Edgar.Geometry.Vector2Int(4, 2))
        }
                                                       );
        var corridorRoomTemplate = new RoomTemplateGrid2D(
            corridorOutline,
            corridorDoors,
            allowedTransformations: new List <TransformationGrid2D>()
        {
            TransformationGrid2D.Identity,
            TransformationGrid2D.Rotate90
        },
            name: "corridorRoomTemplate"
            );

        var corridorRoomTemplateLonger = new RoomTemplateGrid2D(
            PolygonGrid2D.GetRectangle(5, 2),
            new ManualDoorModeGrid2D(new List <DoorGrid2D>()
        {
            new DoorGrid2D(new Edgar.Geometry.Vector2Int(0, 1), new Edgar.Geometry.Vector2Int(0, 2)),
            new DoorGrid2D(new Edgar.Geometry.Vector2Int(5, 1), new Edgar.Geometry.Vector2Int(5, 2))
        }
                                     ),
            allowedTransformations: new List <TransformationGrid2D>()
        {
            TransformationGrid2D.Identity,
            TransformationGrid2D.Rotate90
        },
            name: "corridorRoomTemplateLonger"
            );

        var corridorRoomDescription = new RoomDescriptionGrid2D(
            isCorridor: true,
            roomTemplates: new List <RoomTemplateGrid2D>()
        {
            corridorRoomTemplate, corridorRoomTemplateLonger
        }
            );

        return(corridorRoomDescription);
    }
        public List <RoomTemplateInstanceGrid2D> GetRoomTemplateInstances(RoomTemplateGrid2D roomTemplate)
        {
            var result    = new List <RoomTemplateInstanceGrid2D>();
            var doorLines = roomTemplate.Doors.GetDoors(roomTemplate.Outline);
            var shape     = roomTemplate.Outline;

            foreach (var transformation in roomTemplate.AllowedTransformations)
            {
                var transformedShape = shape.Transform(transformation);
                var smallestPoint    = transformedShape.BoundingRectangle.A;

                // Both the shape and doors are moved so the polygon is in the first quadrant and touches axes
                transformedShape = transformedShape + (-1 * smallestPoint);
                transformedShape = polygonUtils.NormalizePolygon(transformedShape);
                var transformedDoorLines = doorLines
                                           .Select(x => DoorUtils.TransformDoorLine(x, transformation))
                                           .Select(x => new DoorLineGrid2D(x.Line + (-1 * smallestPoint), x.Length, x.DoorSocket))
                                           .ToList();

                // Check if we already have the same room shape (together with door lines)
                var sameRoomShapeFound = false;
                foreach (var roomInfo in result)
                {
                    if (roomInfo.RoomShape.Equals(transformedShape) &&
                        roomInfo.DoorLines.SequenceEqualWithoutOrder(transformedDoorLines))
                    {
                        roomInfo.Transformations.Add(transformation);

                        sameRoomShapeFound = true;
                        break;
                    }
                }

                if (sameRoomShapeFound)
                {
                    continue;
                }

                result.Add(new RoomTemplateInstanceGrid2D(roomTemplate, transformedShape, transformedDoorLines, new List <TransformationGrid2D>()
                {
                    transformation
                }));
            }

            return(result);
        }
Example #13
0
        private RoomDescriptionGrid2D GetBasicRoomDescription()
        {
            var doors           = new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 1);
            var transformations = new List <TransformationGrid2D>()
            {
                TransformationGrid2D.Identity,
                TransformationGrid2D.Rotate90
            };

            var squareRoom1 = new RoomTemplateGrid2D(
                PolygonGrid2D.GetSquare(8),
                doors,
                name: "Square 8x8",
                allowedTransformations: transformations
                );

            var squareRoom2 = new RoomTemplateGrid2D(
                PolygonGrid2D.GetSquare(6),
                doors,
                name: "Square 6x6",
                allowedTransformations: transformations
                );

            var rectangleRoom = new RoomTemplateGrid2D(
                PolygonGrid2D.GetRectangle(6, 10),
                doors,
                name: "Rectangle 6x10",
                allowedTransformations: transformations
                );

            return(new RoomDescriptionGrid2D
                   (
                       isCorridor: false,
                       roomTemplates: new List <RoomTemplateGrid2D>()
            {
                squareRoom1,
                squareRoom2,
                rectangleRoom
            }
                   ));
        }
 public RoomTemplateConfiguration(RoomTemplateGrid2D roomTemplate, Vector2Int position)
 {
     RoomTemplate = roomTemplate;
     Position     = position;
 }
Example #15
0
 public RoomTemplateInfo(List <IntAlias <PolygonGrid2D> > aliases, RoomTemplateGrid2D roomTemplate)
 {
     Aliases      = aliases;
     RoomTemplate = roomTemplate;
 }
Example #16
0
        /// <summary>
        /// Prepare level description.
        /// </summary>
        public LevelDescriptionGrid2D <int> GetLevelDescription()
        {
            //md In this example, we will generate a very simple level consisting of 5 rooms with rectangular shapes.

            //md ## Room templates
            //md First, we will create our room templates. To do that, we need to create a *polygon* that defines the outline of the room template and also provide a list of possible door positions.

            //md ### Outline
            //md In the *Grid2D* setting, the outline of a room template is an orthogonal polygon where each point has integer coordinates. In other words, it is a polygon that we can draw on an integer grid using 1x1 square tiles.

            //md The first outline that we create is a 6x10 rectangle:

            var squareRoomOutline = new PolygonGrid2DBuilder()
                                    .AddPoint(0, 0)
                                    .AddPoint(0, 10)
                                    .AddPoint(6, 10)
                                    .AddPoint(6, 0)
                                    .Build();

            //md > **Note:** Orthogonal (or rectilinear) polygon is a polygon of whose edge intersections are at right angles. When on an integer grid, each side of an orthogonal polygon is aligned with one of the axes.

            //md > **Note:** There are several ways of constructing polygons:
            //md    - `PolygonGrid2D.GetSquare(width)` for squares
            //md    - `PolygonGrid2D.GetRectangle(width, height)` for rectangles
            //md    - `PolygonGrid2DBuilder` with the `.AddPoint(x, y)` method
            //md    - or the `PolygonGrid2D(IEnumerable<Vector2Int> points)` constructor

            //md ### Doors
            //md In order to tell the generator how it can connect individual room templates, we need to specify all the available door positions. The main idea is that the more door positions we provide, the easier it is for the generator to find a valid layout. To define door positions, we use the `IDoorModeGrid2D` interface. The most simple *door mode* is the `SimpleDoorModeGrid2D` - it lets us specify the length of doors and how far from corners of the outline they must be. In this tutorial, we will use doors with length of 1 tile and at least 1 tile away from corners.

            var doors = new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 1);

            //md > **Note:** There is also an additional door mode available - `ManualDoorModeGrid2D`. This mode lets you specify exactly which door positions are available. It is useful for example when we want to have doors only on the two opposite sides of a corridor.

            //md ### Allowed transformations
            //md Optionally, it is also possible to let the generator apply some transformations to the room, e.g. rotate it by 90 degrees or mirror it by the X axis. An advantage of this approach is that the algorithm automatically handles door positions and we do not have to manually define all the variations of the room template.

            var transformations = new List <TransformationGrid2D>()
            {
                TransformationGrid2D.Identity,
                TransformationGrid2D.Rotate90
            };

            //md ### Putting it all together
            //md We can now combine the *outline*, *door mode* and *allowed transformations* together to create our first room template. We also provide a *name* which is optional but it may come in handy if we need to debug something.

            var rectangleRoomTemplate = new RoomTemplateGrid2D(
                squareRoomOutline,
                doors,
                allowedTransformations: transformations,
                name: "Rectangle 6x10"
                );

            //md We can also create a room template in-place with a single expression.

            var squareRoomTemplate = new RoomTemplateGrid2D(
                PolygonGrid2D.GetSquare(8),
                new SimpleDoorModeGrid2D(doorLength: 1, cornerDistance: 1),
                name: "Square 8x8"
                );

            //md Below we can see a visualization of the two room templates. Individual door positions are shown in red.

            //md ![](./basics/room_templates.png)

            //md ## Room description
            //md When we have our room templates ready, we need to create an instance of the `RoomDescriptionGrid2D` class which describes the properties of individual rooms in the level. In this tutorial, all the rooms use the same pool of room templates, so we can create only a single room description and reuse it. However, it is also possible to use different room description for different types of rooms. For example, we may want to have a boss room and a spawn room that should use different room templates than normal rooms.

            var roomDescription = new RoomDescriptionGrid2D
                                  (
                isCorridor: false,
                roomTemplates: new List <RoomTemplateGrid2D>()
            {
                rectangleRoomTemplate, squareRoomTemplate
            }
                                  );

            //md ## Level description
            //md The final step is to describe the structure of the level. We will use a very simple graph of rooms that we can see below:

            //md ![](./basics/graph.png)

            //md First, we have to create an instance of the `LevelDescriptionGrid2D<TRoom>` class. For simplicity, We will use `integers` to identify individual rooms. But it is also possible to use a custom room type by using a different generic type parameter.

            var levelDescription = new LevelDescriptionGrid2D <int>();

            //md Next, we add individual rooms to the level description.

            levelDescription.AddRoom(0, roomDescription);
            levelDescription.AddRoom(1, roomDescription);
            levelDescription.AddRoom(2, roomDescription);
            levelDescription.AddRoom(3, roomDescription);
            levelDescription.AddRoom(4, roomDescription);

            //md And lastly, we describe how should individual rooms be connected.

            levelDescription.AddConnection(0, 1);
            levelDescription.AddConnection(0, 3);
            levelDescription.AddConnection(0, 4);
            levelDescription.AddConnection(1, 2);
            levelDescription.AddConnection(2, 3);


            //md_sc method_content:Run

            return(levelDescription);
        }
 /// <summary>
 ///     Computes a room room template from a given room template game object.
 /// </summary>
 /// <param name="roomTemplatePrefab"></param>
 /// <param name="roomTemplate"></param>
 /// <param name="result"></param>
 /// <returns></returns>
 public static bool TryGetRoomTemplate(GameObject roomTemplatePrefab, out RoomTemplateGrid2D roomTemplate, out ActionResult result)
 {
     return(RoomTemplateLoaderGrid2D.TryGetRoomTemplate(roomTemplatePrefab, out roomTemplate, out result));
 }
Example #18
0
        /// <summary>
        /// Prepare level description.
        /// </summary>
        public LevelDescriptionGrid2D <int> GetLevelDescription()
        {
            //md By default, rooms in generated levels are connected directly - there are no corridors between them. If we want to use corridors, we have to add a corridor room between all pairs of neighboring rooms.

            //md > **Note:** As of now, the whole level geometry is fixed - the generator works only with the room templates that we create at design time. That means that we have to manually create all the shapes of corridor rooms. In the future, I would like to experiment with using path-finding for corridors instead of predefined room templates.

            //md ## Corridor room description
            //md First, we create the outline for the corridor room template. The performance of the generator is the best with rather short corridors, so we will use a 2x1 rectangle:

            var corridorOutline = PolygonGrid2D.GetRectangle(2, 1);

            //md The next step is to add doors. We can no longer use the simple door mode because we want to have exactly two door positions on the opposite sides of the corridor, which is not possible with the simple mode. With the manual mode, we have to specify all the door positions manually.

            var corridorDoors = new ManualDoorModeGrid2D(new List <DoorGrid2D>()
            {
                new DoorGrid2D(new Vector2Int(0, 0), new Vector2Int(0, 1)),
                new DoorGrid2D(new Vector2Int(2, 0), new Vector2Int(2, 1))
            }
                                                         );

            //md Now we can create the corridor room template. We must not forget to allow the 90 degrees rotation because, otherwise we would not be able to connect rooms both vertically and horizontally.

            var corridorRoomTemplate = new RoomTemplateGrid2D(
                corridorOutline,
                corridorDoors,
                allowedTransformations: new List <TransformationGrid2D>()
            {
                TransformationGrid2D.Identity,
                TransformationGrid2D.Rotate90
            }
                );

            //md We can also add another corridor room template which is a little bit longer then the previous one:

            var corridorRoomTemplateLonger = new RoomTemplateGrid2D(
                PolygonGrid2D.GetRectangle(4, 1),
                new ManualDoorModeGrid2D(new List <DoorGrid2D>()
            {
                new DoorGrid2D(new Vector2Int(0, 0), new Vector2Int(0, 1)),
                new DoorGrid2D(new Vector2Int(4, 0), new Vector2Int(4, 1))
            }
                                         ),
                allowedTransformations: new List <TransformationGrid2D>()
            {
                TransformationGrid2D.Identity,
                TransformationGrid2D.Rotate90
            }
                );

            //md Below we can see a visualization of the two room templates:

            //md ![](./corridors/room_templates.png)

            //md And finally, we can create the corridor room description. We must not forget to set the `IsCorridor` flag to `true`.

            var corridorRoomDescription = new RoomDescriptionGrid2D
                                          (
                isCorridor: true,
                roomTemplates: new List <RoomTemplateGrid2D>()
            {
                corridorRoomTemplate, corridorRoomTemplateLonger
            }
                                          );

            //md ## Basic room description
            //md For non-corridor rooms, we will use three rectangular room templates - 6x6 square, 8x8 square and 6x10 rectangle. The full code is omitted for simplicity.

            var basicRoomDescription = GetBasicRoomDescription();

            //md ## Level description
            //md First, we create a level description.

            var levelDescription = new LevelDescriptionGrid2D <int>();

            //md Next, we create a graph of rooms. Instead of adding rooms and connections directly to the level description, it might be sometimes beneficial to first prepare the graph data structure itself and then go through individual rooms and connections and add them to the level description.

            var graph = new UndirectedAdjacencyListGraph <int>();

            graph.AddVerticesRange(0, 13);

            graph.AddEdge(0, 1);
            graph.AddEdge(0, 2);
            graph.AddEdge(0, 8);
            graph.AddEdge(1, 3);
            graph.AddEdge(1, 4);
            graph.AddEdge(1, 5);
            graph.AddEdge(2, 6);
            graph.AddEdge(2, 7);
            graph.AddEdge(5, 9);
            graph.AddEdge(6, 9);
            graph.AddEdge(8, 10);
            graph.AddEdge(8, 11);
            graph.AddEdge(8, 12);

            //md > **Note:** As we want to have corridors between all neighboring rooms, it is better to create the graph only with non-corridor rooms and then add corridor rooms programatically.

            //md When we have the graph ready, we can add non-corridor rooms:

            foreach (var room in graph.Vertices)
            {
                levelDescription.AddRoom(room, basicRoomDescription);
            }

            //md Before we add corridor rooms, we have to figure out how to identify them. As we use integers, probably the easiest way is to number the corridor rooms and keep track which was the last used number:

            var corridorCounter = graph.VerticesCount;

            //md Now we can add corridor rooms. For each edge of the original graph, we create a corridor room and connect it to the two non-corridor rooms:

            foreach (var connection in graph.Edges)
            {
                // We manually insert a new room between each pair of neighboring rooms in the graph
                levelDescription.AddRoom(corridorCounter, corridorRoomDescription);

                // And instead of connecting the rooms directly, we connect them to the corridor room
                levelDescription.AddConnection(connection.From, corridorCounter);
                levelDescription.AddConnection(connection.To, corridorCounter);

                corridorCounter++;
            }

            return(levelDescription);
        }