Generate Mazes via API¶
Creating labyrinths programmatically via the API offers the same level of customization and control as the command-line tool, but with the flexibility and integration capabilities of a Python script. Below is a concise guide to generating mazes using the Erbsland Maze API.
Start by importing the necessary classes from the erbsland_maze
module. This includes setup for the SVG output, layout configurations, modifiers to customize the maze, and the generator itself. The pathlib
module is used for file path operations, ensuring compatibility across different operating systems.
>>> from erbsland_maze import SvgSetup, SvgLayout, BlankModifier, Placement, RoomSize, GeneratorSetup, Generator
>>> from pathlib import Path
>>> svg_setup = SvgSetup(width=100.0, height=100.0, side_length=5.0)
>>> svg_layout = SvgLayout(svg_setup)
>>> modifiers = [BlankModifier(Placement.CENTER, RoomSize(5, 5))]
>>> generator_setup = GeneratorSetup(modifiers=modifiers)
>>> generator = Generator(svg_layout)
>>> svg_file = Path('maze.svg')
>>> generator.generate_and_save(svg_file)
Erbsland Maze - V1.1
Layout: 100.00 x 100.00 mm / thickness 1.70 mm / calculated side length: 4.76 mm
Room count: 21 x 21
Preparing rooms...
1. attempt to find a solution.
Generating the paths for the maze...
Filling islands...
Verifying generated paths...
Connect all paths...
- successfully joined paths 1-2
Rendering image...
In this example, a maze with a dimension of 100x100 mm is created, with a specified side length of 5.0 mm for each room. A BlankModifier
is used to create a blank area in the center of the maze, demonstrating how to apply customizations. The maze generation process is initiated, and the resulting SVG is saved to a file named “maze.svg”.
This approach provides a powerful way to integrate maze generation into applications, allowing for dynamic creation and manipulation of mazes based on user input or other runtime conditions.
Step by Step¶
Generating a maze programmatically involves a series of steps that allow you to customize every aspect of the maze, from its layout and dimensions to specific features like end points and blank spaces. Here’s a step-by-step guide to creating a maze using the Erbsland Maze API:
Initialize the Layout: Start by creating an instance of the
Layout
class for theGenerator
. The API provides anSvgLayout
class, which is designed to work with SVG output. This class requires an instance ofSvgSetup
that contains the initial setup parameters, including dimensions and side length.Configure the Generator: If you wish to customize your maze, prepare a
GeneratorSetup
instance next. This setup allows you to add modifications such as end points, blank spaces, or any other modifiers to the maze’s layout.Instantiate the Generator: With your
SvgLayout
andGeneratorSetup
ready, create a newGenerator
instance. Pass the previously preparedSvgLayout
andGeneratorSetup
to the constructor of theGenerator
.Generate and Save the Maze: To kick off the maze generation process and save the output, call the
Generator.generate_and_save()
method on theGenerator
instance, providing apathlib.Path
object that specifies the filename and location for the generated SVG file.
For subsequent mazes with the same layout but different configurations or to introduce randomness, you can call the Generator.generate_and_save()
method multiple times. Each call generates a new maze according to the current GeneratorSetup
configuration.
Feel free to adjust the settings in your GeneratorSetup
between generations to explore different maze layouts and features. However, should you need to modify the maze’s dimensions or fundamental layout, you will need to instantiate a new Layout
and Generator
.
The Generator¶
At the heart of the maze generation process lies the Generator
, which leverages an abstract algorithm to construct the maze. This component works hand-in-hand with a Layout
class, tasked with transforming the conceptual room layout into a tangible image.
- class erbsland_maze.Generator(layout: Layout, setup: GeneratorSetup)¶
Essential to the maze generation, the
Generator
orchestrates the creation process, guided by aLayout
instance for graphical representation and aGeneratorSetup
for procedural directives.- Parameters:
layout (Layout) – Specifies the graphical framework for maze generation.
setup (GeneratorSetup) – Dictates the generation strategy and maze configuration.
- generate_and_save(path)¶
Executes the maze generation and commits the final image to file.
- Parameters:
path (pathlib.Path) – Designates the file path for the saved maze image.
The GeneratorSetup
class is instrumental in fine-tuning the generation process, offering a wide array of parameters to customize the maze’s layout, appearance, and complexity.
- class erbsland_maze.GeneratorSetup(path_ends=None, modifiers=None, allow_islands=True, maximum_attempts=20, verbose=True, ignore_errors=False, layout_only=False)¶
Configures the operational parameters for the
Generator
, influencing everything from path dynamics to visual modifiers.- Parameters:
path_ends (list[PathEnd]) – A list of path-ends in the maze..
modifiers (list[Modifier]) – A list of modifiers to customize the maze layout..
allow_islands (bool) – Allows isolated sections in the maze. They will filled with random paths as decorations. If set to
False
, isolated sections raise an exception.maximum_attempts (int) – Caps the attempts to resolve the maze.
verbose (bool) – Enables or disables console updates throughout the generation process.
ignore_errors (bool) – Allows the process to continue past errors, useful for debugging.
layout_only (bool) – If enabled, there is no maze generated and just the room layout saved into the image.
The SVG Layout¶
This project currently provides only built-in support to generate SVG files using the PyCairo library. In order to render the mazes in SVG files, you have to create an instance of the SvgLayout
class and pass it to the constructor of Generator
.
- class erbsland_maze.SvgLayout(setup: SvgSetup)¶
The SVG layout class renders the generated maze into a SVG file using PyCairo. It takes one parameter setup that contains all dimensions and settings defining the rendered maze.
- Parameters:
setup (SvgSetup) – The setup values for the SVG layout.
- class erbsland_maze.SvgSetup¶
This class provides all attributes for the SVG layout.
- width: float¶
This mandatory attribute specifies the width of the maze in millimeters (mm). The width impacts the final dimensions of the generated SVG file. When used alongside the
side_length
, the layout calculates the optimal number of rooms along the X axis.
- height: float¶
This required attribute sets the height of the maze in millimeters (mm). Similar to width, height determines the dimensions of the resulting SVG file. In combination with the
side_length
attribute, it helps in determining the ideal number of rooms along the Y axis.
- wall_thickness: float = 1.7¶
Defines the thickness of the maze’s walls with this option, measured in millimeters (mm). If not specified, a default thickness of 1.7 mm is applied.
- side_length: float = 4.0¶
This parameter establishes the side length of each room within the maze, including wall thickness, measured in millimeters (mm). The default value is 4 mm.
Note
If the maze’s specified width and height do not proportionately match the room length set by this option, the outer rooms will be adjusted in size to ensure the entire area is filled.
- width_parity: Parity = Parity.ODD¶
This option allows you to determine the parity (odd or even) of the room count along the X axis.
- height_parity: Parity = Parity.ODD¶
Similarly, this option lets you set the parity (odd or even) of the room count along the Y axis.
- start_end_mark: bool = True¶
this flag controls if the colored rectangle markers at the path ends will be painted or not. Setting this attribute to
False
is particularly beneficial for integrating the maze generation into automated workflows, where such markers may not be needed.
- svg_unit: SvgUnit = SvgUnit.MM¶
Select the unit of measurement for the SVG file’s dimensions.
Note
Switching to
SvgUnit.PX
(pixels) modifies the unit within the SVG file only and does not affect the input dimensions (width
,height
, orside_length
), which should always be provided in millimeters.
- svg_dpi: float = 96.0¶
Define the DPI (dots per inch) for converting millimeter measurements to pixels in the SVG output. The default setting is 96 DPI, and the acceptable range spans from 60 to 10,000 DPI.
- svg_zero: SvgZeroPoint = SvgZeroPoint.CENTER¶
Adjust the origin point of the SVG canvas.
Parameter
Meaning
Places the maze’s center at the middle of the canvas, ensuring all SVG coordinates are positive from the document’s top-left corner. This is the default and best choice for viewing the SVG or using it for designs, web or print.
Moves the zero point to the top-left corner of the document, beneficial for workflows requiring the maze’s center at the document’s origin, though it may not display correctly in all viewers.
- svg_background: bool = True¶
This flag controls if the SVG background shall be drawn opaque.
- class erbsland_maze.Parity(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
Requesting a parity of a number of elements.
- EVEN = 'even'¶
Even parity requested.
- NONE = 'none'¶
No parity requested.
- ODD = 'odd'¶
Odd parity requested.
- class erbsland_maze.SvgFillMode(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
The mode how the actual side length is calculated.
- FIXED_CENTER = 'fixed_center'¶
Use a square room size with the exact side length as configured and place the maze in the center. If the room size doesn’t divide the with and height evenly, there will be a gap around the maze.
- FIXED_TOP_LEFT = 'fixed_top_left'¶
Use a square room size with the exact side length as configured and place the maze in the top left corner. If the room size doesn’t divide the with and height evenly, there will be a gap at the bottom or right side.
- SQUARE_CENTER = 'square_center'¶
Use a square room size that fills at least one dimension perfectly, and align the maze at the top left corner. If the room size doesn’t divide the with and height evenly, there will be a gap around the maze.
- SQUARE_TOP_LEFT = 'square_top_left'¶
Use a square room size that fills at least one dimension perfectly, and align the maze at the top left corner. If the room size doesn’t divide the with and height evenly, there will be a gap at the bottom or right side.
- STRETCH = 'stretch'¶
Stretch the rooms into rectangles that completely fill the specified width and height.
- STRETCH_EDGE = 'stretch_edge'¶
Calculate the best square room size from the side lengths and parity and stretch the rooms at the edges to completely fill the specified width and height.
- does_center_rooms() bool ¶
Tests if this value centers the room.
- does_proportionally_scale_room() bool ¶
Tests if this value scales the room size to fill the area.
- does_scale_room() bool ¶
Tests if this value scales the room, proportionally or not.
- does_stretch_edge() bool ¶
Tests if this value stretches the maze edge.
- classmethod from_name(name: str) Self ¶
Get an instance from the given name.
- Parameters:
name – The name.
- Returns:
The enum value.
- classmethod from_text(text: str) Self ¶
Parse a text and convert it to a fill mode.
- Parameters:
text – The text to parse.
- Returns:
The enum value.
- classmethod get_all_names() list[str] ¶
Get all possible names for the fill modes.
- class erbsland_maze.SvgUnit(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
SVG units to use for a document.
- MM = 0¶
Millimetre unit.
- PX = 1¶
Pixel unit.
- class erbsland_maze.SvgZeroPoint(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
Where the SVG zero point shall be placed, which is the center of the maze.
- CENTER = 'center'¶
Create a SVG file for print, where the center is at the center of the canvas.
- TOP_LEFT = 'top_left'¶
Create a technical SVG file, where the center is at the top left of the canvas.
Path Ends¶
- class erbsland_maze.PathEnd(placement: ~erbsland_maze.placement.Placement, offset: ~erbsland_maze.room_offset.RoomOffset = <factory>, is_dead_end: bool = False, name: str = '')¶
Represents the end of a connected path. This can also be an intermediate point of the path, that must be connected.
- classmethod from_text(text: str)¶
Create a path end by parsing the given text.
- Parameters:
text – The text to parse.
- Returns:
A new path end.
- is_dead_end: bool = False¶
If this path end is a dead-end and does not connect any other path ends. A such path can be cut short to allow connecting the real paths.
- name: str = ''¶
The name that was used to configure this path. Used in error messages.
- offset: RoomOffset¶
The offset from this placement.
Modifier Classes¶
- class erbsland_maze.Modifier(modifier_type: ModifierType, placement: Placement = None, size: RoomSize = None, insets: RoomInsets = None, offset: RoomOffset = None, closing: Closing = None, name: str = None)¶
The base class of all modifiers to style the maze in custom ways.
Do not use this class directly. Use the derived classes instead.
- abstract classmethod from_text(text: str) Self ¶
Create a modifier from a string.
- Parameters:
text – The text that will be parsed.
- Returns:
The modifier object.
- class erbsland_maze.BlankModifier(placement: Placement, size: RoomSize = RoomSize(width=1, height=1), offset: RoomOffset = RoomLocation(0, 0, is_relative=False), name: str = None)¶
A modifier to create blank areas in the maze.
- classmethod from_text(text: str) Self ¶
Create a modifier from a string.
- Parameters:
text – The text that will be parsed.
- Returns:
The modifier object.
- class erbsland_maze.FrameModifier(insets: RoomInsets = RoomInsets(north=1, east=1, south=1, west=1), name: str = None)¶
A modifier to create a frame of blank rooms around the maze.
- classmethod from_text(text: str) Self ¶
Create a modifier from a string.
- Parameters:
text – The text that will be parsed.
- Returns:
The modifier object.
- class erbsland_maze.ClosingModifier(closing: Closing, placement: Placement, size: RoomSize = RoomSize(width=1, height=1), offset: RoomOffset = RoomLocation(0, 0, is_relative=False), name: str = None)¶
A modifier to close paths in the maze.
- classmethod from_text(text: str) Self ¶
Create a modifier from a string.
- Parameters:
text – The text that will be parsed.
- Returns:
The modifier object.
- class erbsland_maze.Closing(closing_type: ClosingType, invert: bool = False)¶
A closing specification.
- class erbsland_maze.MergeModifier(placement: Placement, size: RoomSize = RoomSize(width=1, height=1), offset: RoomOffset = RoomLocation(0, 0, is_relative=False), name: str = None)¶
A modifier to merge rooms in the maze.
- classmethod from_text(text: str) Self ¶
Create a modifier from a string.
- Parameters:
text – The text that will be parsed.
- Returns:
The modifier object.
Modifier Enumerations¶
- class erbsland_maze.ModifierType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
The type of modifier.
- BLANK = 'blank'¶
Create a blank space at the specified location.
- CLOSING = 'close'¶
Permanently closes connections in portions of the maze
- FRAME = 'frame'¶
Creates a blank space all around the maze with the specified size.
- MERGE = 'merge'¶
Merge rooms into a larger room at the specified location.
- class erbsland_maze.Placement(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
Logical placement of an element.
- direction_normals() Tuple[int, int] ¶
Get normals to detect the direction of this placement.
- offset(value: int) RoomLocation ¶
Get an offset that points towards the center.
- Parameters:
value – The number of rooms toward the center.
- Returns:
The offset as room location.
- property order_value: int¶
Return a value to order modifications in a sequence to case the least amount of conflicts.
- placement_normals() Tuple[float, float] ¶
Get normals to get a placement.
- size_offset(size: RoomSize) RoomLocation ¶
A size offset to correct a placement according to the size of the affected locations.
- Parameters:
size – The size.
- Returns:
The offset as room location.
- class erbsland_maze.ClosingType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
Room Layout Classes¶
- class erbsland_maze.Room(location: RoomLocation)¶
A room in the maze.
- add_connection(location: RoomLocation, direction: Direction, target_room: Room) None ¶
Add a connection to another room.
- Parameters:
location – The location inside of this room.
direction – The direction for the wall in which this connection is anchored.
target_room – The target room for the connection.
- close_blocked_connections() None ¶
Remove all connections from this room, that are blocked because they lead to already allocated paths.
- get_connection(wall: Wall) RoomConnection | None ¶
Get a connection at the given wall.
- Parameters:
wall – The wall.
- Returns:
The connection at the given wall or None if there isn’t one.
- get_connections_at_location(location: RoomLocation) list[RoomConnection] ¶
Get all connections from a given location inside this room.
- Parameters:
location – The location inside of this room.
- Returns:
A list of connections.
- get_connections_in_direction(direction: Direction) list[RoomConnection] ¶
Get all connections that lead to the given direction.
- Parameters:
direction – The direction.
- Returns:
A list of connections.
- is_connected_to_room(room: Room) bool ¶
Test if this room has a connection to another room.
- Parameters:
room – The other room to test.
- Returns:
True if there is a connection between this and the other room.
- is_open_connection(wall: Wall) bool ¶
Test if there is an open connection to the given wall.
- Parameters:
wall – The wall.
- Returns:
True if there is an open connection.
- property is_surrounded_by_blanks: bool¶
Test if the room is surrounded by blank rooms.
This test is used to check if a room is suitable for a start position. For example, if there is a frame around the maze, and the start position is in the corner, this will never work.
- remove_all_connections()¶
Remove all connections from and to this room.
- remove_connection(connection: RoomConnection) None ¶
Remove a connection from this room.
- Parameters:
connection – The connection to remove.
- reset()¶
Reset the room for another solution attempt.
- unused_connections() list[RoomConnection] ¶
Get all connections that can be potentially used to create a new path.
- Returns:
A list of connections.
- class erbsland_maze.RoomConnection(a: ConnectionSide, b: ConnectionSide)¶
A connection between two rooms.
- property connects_primary_paths: bool¶
Test if this connection connects primary paths and no decoy paths.
- property connects_two_paths: bool¶
Test if this connection connects two paths.
- get_path_join_info() PathJoinInfo ¶
A method, to get a key for the path joining info.
- Returns:
A tuple containing the two path ids and the total path length.
- local(my_room: Room) ConnectionSide ¶
Get my local side of the connection.
- Parameters:
my_room – My room to get the side of.
- Returns:
The connection side.
- remote(my_room: Room) ConnectionSide ¶
Get the remote side of the connection.
- Parameters:
my_room – My room, to get the remote side from.
- Returns:
The connection side.
- remote_room(my_room: Room) Room ¶
Shortcut to get the remote room.
- Parameters:
my_room – My room.
- Returns:
The remote room.
- replace_room(old_room: Room, new_room: Room) None ¶
Replace a room in this connection.
- Parameters:
old_room – The old room.
new_room – The new room.
- reset()¶
Reset the connection for another solution attempt.
- property total_path_length: int¶
Get the total path length at this connection.
- class erbsland_maze.ConnectionSide(room: Room, wall: Wall)¶
Represents the end or side of a connection.
- class erbsland_maze.RoomLocation(x: int = 0, y: int = 0)¶
The location of a room in room units.
- advance(direction: Direction) RoomLocation ¶
Get a new room location that is in the given direction.
- Parameters:
direction – The direction.
- Returns:
The new room location.
- classmethod from_text(text: str) RoomLocation ¶
Create a room location from a given text.
- Parameters:
text – The text to parse.
- Returns:
The room location.
- translated(delta_x: int, delta_y: int) RoomLocation ¶
Get a translated room location, with the given delta.
- Parameters:
delta_x – The delta in the X direction.
delta_y – The delta in the Y direction.
- Returns:
The new room location.
- x: int = 0¶
The x coordinate of the room.
- y: int = 0¶
The y coordinate of the room.
- class erbsland_maze.RoomSize(width: int = 0, height: int = 0)¶
The size of a room in room units.
- classmethod from_text(text: str) Self ¶
Create a room size from the given text.
The text can be a name like “single”, “small”, “medium” or “large”, or a single positive integer, or two integer seperated by a comma.
- Parameters:
text – The text to parse.
- Returns:
A room size.
- class erbsland_maze.Wall(location: RoomLocation, direction: Direction)¶
A wall in a room.
- location: RoomLocation¶
The location in the room where the wall is.
- matches_closing_type(closing_type: ClosingType, grid: LocationGrid) bool ¶
Test if this wall matches the closing type in relation to the given room grid.
- Parameters:
closing_type – The closing type.
grid – The room grid.
- Returns:
True if the wall matches the closing type.
- class erbsland_maze.RoomInsets(north: int = 0, east: int = 0, south: int = 0, west: int = 0)¶
Room location insets.
- classmethod from_text(text: str) Self ¶
Create an inset definition from the given text.
The text can be a single positive integer, or two, or four integer seperated by a comma.
- Parameters:
text – The text to parse.
- Returns:
A room size.
- static value_from_text(text: str) int ¶
Convert a text into an inset value.
- Parameters:
text – The text to convert.
- Returns:
The resulting value.
- class erbsland_maze.RoomOffset(x: int = 0, y: int = 0, is_relative: bool = False)¶
- is_relative: bool = False¶
A relative positive offset moves the room from the placement towards the center.
- property is_zero: bool¶
Test if this offset does nothing.
- translate_location(location: RoomLocation, placement: Placement) RoomLocation ¶
Return a new location with this offset and placement.
- Parameters:
location – The start location.
placement – The placement.
- Returns:
The new location with this offset applied.
- x: int = 0¶
The offset in x direction, or the length for a relative offset.
- y: int = 0¶
The offset in y direction. Ignored for relative offsets.
- class erbsland_maze.LocationGrid(location: RoomLocation, size: RoomSize)¶
A rectangular grid of room locations.
- all_frame_locations(insets: RoomInsets = RoomInsets(north=1, east=1, south=1, west=1)) list[RoomLocation] ¶
Get all locations in this grid that are part of the frame.
- Parameters:
insets – The insets of the frame.
- Returns:
All locations that are part of the frame.
- all_locations()¶
Get all locations in this room grid.
- contains(location: RoomLocation) bool ¶
Test if the given location is part of this grid.
- Parameters:
location – The tested location.
- Returns:
True if it is inside of this grid.
- get_corner(corner: Corner) RoomLocation ¶
Get the location a corner.
- Parameters:
corner – The corner.
- Returns:
The location of the corner.
- get_middle(direction: Direction) RoomLocation ¶
Get a middle location in the given direction.
- Parameters:
direction – The direction.
- Returns:
The location.
- is_corner(location: RoomLocation, corner: Corner = None) bool ¶
Test if the location is a corner.
- Parameters:
location – The location to compare.
corner – A specific corner, or None for any corner.
- Returns:
True if the location is a corner.
- is_frame(location: RoomLocation, insets: RoomInsets = RoomInsets(north=1, east=1, south=1, west=1)) bool ¶
Test if the given location is part of the frame of this grid.
- Parameters:
location – The tested location.
insets – The size of the frame.
- Returns:
True if the room is part of the frame.
- is_middle(location: RoomLocation, direction: Direction = None) bool ¶
Test is the given location is at the middle location in the given direction.
- Parameters:
location – The location.
direction – The specific direction, or None for all directions.
- Returns:
True if the given location is at the middle.
- location: RoomLocation¶
The top left corner of the room grid.
- location_for_placement_and_size(placement: Placement, size: RoomSize) RoomLocation ¶
Get the location of the given placement.
- Parameters:
placement – The placement.
size – The size of the modification.
- Returns:
The location of the given placement.
Room Layout Enumerations¶
- class erbsland_maze.RoomType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
The type of room.
- BLANK = 2¶
A blank spot in the maze.
- END = 3¶
A path end.
- PATH = 1¶
A path through the maze.
- class erbsland_maze.Direction(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
A direction in the maze.
- class erbsland_maze.Corner(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)¶
A corner of a room or maze.
- BOTTOM_LEFT = 'bottom_left'¶
The bottom left corner.
- BOTTOM_RIGHT = 'bottom_right'¶
The bottom right corner.
- TOP_LEFT = 'top_left'¶
The top left corner.
- TOP_RIGHT = 'top_right'¶
The top right corner.
- opposite()¶
Get the opposite corner.
The Graphical Layout Classes¶
- class erbsland_maze.Layout¶
The base class for all graphical layout classes.
- abstract get_dimension_info() str ¶
Get dimensional information to be displayed on the console after initialization.
- Returns:
Text that contains the most useful dimension information.
Exception Classes¶
- exception erbsland_maze.GeneratorError¶
An error occurred while generating the maze.