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
Layoutclass for theGenerator. The API provides anSvgLayoutclass, which is designed to work with SVG output. This class requires an instance ofSvgSetupthat contains the initial setup parameters, including dimensions and side length.Configure the Generator: If you wish to customize your maze, prepare a
GeneratorSetupinstance 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
SvgLayoutandGeneratorSetupready, create a newGeneratorinstance. Pass the previously preparedSvgLayoutandGeneratorSetupto 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 theGeneratorinstance, providing apathlib.Pathobject 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 Generator(layout: Layout, setup: GeneratorSetup)
Essential to the maze generation, the
Generatororchestrates the creation process, guided by aLayoutinstance for graphical representation and aGeneratorSetupfor 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 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 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 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_lengthattribute, 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
Falseis 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.
- background_color: Color = Color(0.8, 0.8, 0.8, 1.0)
Defines the background color used in the rendered SVG image, assuming the background drawing is enabled via the
svg_backgroundflag. This allows you to fully customize the appearance of the SVG’s canvas background. The color is expressed as aColorobject using RGBA format with floating-point values between 0.0 and 1.0.
- room_color: Color = Color(0.2, 0.2, 0.2, 1.0)
Sets the color used to draw the maze paths—i.e., the rooms that form the maze layout. This option controls the overall tone of the maze drawing itself. The value is specified as a
Colorobject in RGBA format, allowing for transparency and fine-grained control over appearance.
- endpoint_colors: list[Color] = []
Specifies the colors used to highlight the maze’s path endpoints. This list defines the color for each individual endpoint in the order they are defined.
If the list is left empty, a set of default colors is automatically assigned, cycling through a full color wheel for visual distinction. When fewer colors are provided than there are endpoints, the system will repeatedly cycle through your custom list until every endpoint is assigned a color.
Each color in the list must be defined using the
Colorclass.
- class Parity(*values)
Requesting a parity of a number of elements.
- NONE = 'none'
No parity requested.
- ODD = 'odd'
Odd parity requested.
- EVEN = 'even'
Even parity requested.
- class SvgFillMode(*values)
The mode how the actual side length is calculated.
- 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.
- STRETCH = 'stretch'
Stretch the rooms into rectangles that completely fill the specified width and height.
- 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.
- 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.
- 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.
- 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.
- does_stretch_edge() bool
Tests if this value stretches the maze edge.
- does_scale_room() bool
Tests if this value scales the room, proportionally or not.
- does_proportionally_scale_room() bool
Tests if this value scales the room size to fill the area.
- does_center_rooms() bool
Tests if this value centers the room.
- classmethod get_all_names() list[str]
Get all possible names for the fill modes.
- 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.
- class SvgUnit(*values)
SVG units to use for a document.
- MM = 0
Millimetre unit.
- PX = 1
Pixel unit.
- class SvgZeroPoint(*values)
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.
- class Color(r: float = 0.0, g: float = 0.0, b: float = 0.0, a: float = 1.0)
Represents an RGBA color with channels normalized between 0.0 and 1.0.
- static for_endpoint(index: int, total_count: int) Color
Create the default color for an endpoint.
- Parameters:
index – The index of the endpoint.
total_count – The total number of endpoints.
- Returns:
A color object.
- static from_text(value: str) Color
Create a Color instance from a string representation.
- Supported formats:
Hex: #RGB, #RGBA, #RRGGBB, #RRGGBBAA
RGB: rgb(r, g, b) or rgb(r, g, b, a)
HSL: hsl(h, s%, l%) or hsl(h, s%, l%, a)
- Parameters:
value – The color string.
- Returns:
A new Color instance.
- Raises:
ValueError – If the format is unsupported or channels are out of range.
Path Ends
- class PathEnd(placement: Placement, 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.
- offset: RoomOffset
The offset from this placement.
- 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.
- 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.
Modifier Classes
- class 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.
- abstractmethod 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 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 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 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 Closing(closing_type: ClosingType, invert: bool = False)
A closing specification.
- class 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 ModifierType(*values)
The type of modifier.
- BLANK = 'blank'
Create a blank space at the specified location.
- FRAME = 'frame'
Creates a blank space all around the maze with the specified size.
- CLOSING = 'close'
Permanently closes connections in portions of the maze
- MERGE = 'merge'
Merge rooms into a larger room at the specified location.
- class Placement(*values)
Logical placement of an element.
- direction_normals() Tuple[int, int]
Get normals to detect the direction of this placement.
- placement_normals() Tuple[float, float]
Get normals to get a 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.
- 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.
- property order_value: int
Return a value to order modifications in a sequence to case the least amount of conflicts.
- class ClosingType(*values)
Room Layout Classes
- class Room(location: RoomLocation)
A room in the maze.
- 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.
- close_blocked_connections() None
Remove all connections from this room, that are blocked because they lead to already allocated paths.
- unused_connections() list[RoomConnection]
Get all connections that can be potentially used to create a new path.
- 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.
- 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_in_direction(direction: Direction) list[RoomConnection]
Get all connections that lead to the given direction.
- Parameters:
direction – The direction.
- Returns:
A list of connections.
- 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.
- 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.
- 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.
- remove_connection(connection: RoomConnection) None
Remove a connection from this room.
- Parameters:
connection – The connection to remove.
- remove_all_connections()
Remove all connections from and to this room.
- reset()
Reset the room for another solution attempt.
- class RoomConnection(a: ConnectionSide, b: ConnectionSide)
A connection between two rooms.
- property connects_two_paths: bool
Test if this connection connects two paths.
- property connects_primary_paths: bool
Test if this connection connects primary paths and no decoy paths.
- property total_path_length: int
Get the total path length at this connection.
- 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.
- class RoomLocation(x: int = 0, y: int = 0)
The location of a room in room units.
- x: int = 0
The x coordinate of the room.
- y: int = 0
The y coordinate of the room.
- advance(direction: Direction) RoomLocation
Get a new room location that is in the given direction.
- Parameters:
direction – The direction.
- Returns:
The new 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.
- classmethod from_text(text: str) RoomLocation
Create a room location from a given text.
- Parameters:
text – The text to parse.
- Returns:
The room location.
- class 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 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 RoomInsets(north: int = 0, east: int = 0, south: int = 0, west: int = 0)
Room location insets.
- static value_from_text(text: str) int
Convert a text into an inset value.
- Parameters:
text – The text to convert.
- Returns:
The resulting value.
- 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.
- class RoomOffset(x: int = 0, y: int = 0, is_relative: bool = False)
- 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.
- 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.
- class LocationGrid(location: RoomLocation, size: RoomSize)
A rectangular grid of room locations.
- location: RoomLocation
The top left corner of the room grid.
- get_corner(corner: Corner) RoomLocation
Get the location a corner.
- Parameters:
corner – The corner.
- Returns:
The location of the corner.
- 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.
- get_middle(direction: Direction) RoomLocation
Get a middle location in the given direction.
- Parameters:
direction – The direction.
- Returns:
The location.
- 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.
- 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.
- all_locations()
Get all locations in this room grid.
- 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.
- 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.
- 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 RoomType(*values)
The type of room.
- PATH = 1
A path through the maze.
- BLANK = 2
A blank spot in the maze.
- END = 3
A path end.
- class Direction(*values)
A direction in the maze.
The Graphical Layout Classes
- class Layout
The base class for all graphical layout classes.
- abstractmethod initialize() RoomSize
Initializes the graphical layout and calculate the number of rooms required to fill the canvas.
- Returns:
The number of rooms in the X and Y axis.
- abstractmethod render_image(file_path: Path, rooms: list[Room], path_end_rooms: list[Room]) None
Render the maze into an image.
- Parameters:
file_path – The path for the resulting image.
rooms – A list of rooms to render.
path_end_rooms – The end points in the maze to be marked.
- abstractmethod 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 GeneratorError
An error occurred while generating the maze.