Source code for pyrat.src.mazes.holes_on_side_random_maze

##########################################################################################
########################################## INFO ##########################################
##########################################################################################

# This file is part of the PyRat library.
# It is meant to be used as a library, and not to be executed directly.
# Please import necessary elements using the following syntax:
#     from pyrat import <element_name>

"""
This module provides a maze that is created by adding cells from the center of the maze.
It extends ``RandomMaze`` to create a specific type of maze with holes distributed on the sides of the maze.
"""

##########################################################################################
######################################### IMPORTS ########################################
##########################################################################################

# PyRat imports
from pyrat.src.mazes.random_maze import RandomMaze
from pyrat.src.game.exceptions import PyRatException

##########################################################################################
######################################### CLASSES ########################################
##########################################################################################

[docs] class HolesOnSideRandomMaze (RandomMaze): """ *(This class inherits from* ``RandomMaze`` *).* With this maze, holes are distributed on the sides of the maze. The maze is created by adding cells from the center of the maze You can use this class to create a maze with this algorithm. However, if you just want to play a game, you can use the ``Game`` class instead, which will create a maze for you. Just make sure to set the ``random_maze_algorithm`` parameter to ``RandomMazeAlgorithm.HOLES_ON_SIDE`` when creating the game. """ ################################################################################## # CONSTRUCTOR # ##################################################################################
[docs] def __init__ ( self, cell_percentage: float, *args: object, **kwargs: object ) -> None: """ Initializes a new instance of the class, and generates the maze. Args: cell_percentage: Percentage of cells to be reachable. *args: Arguments to pass to the parent constructor. **kwargs: Keyword arguments to pass to the parent constructor. """ # Check validity if not isinstance(cell_percentage, float): raise PyRatException(f"Argument 'cell_percentage' must be a real number of type float (e.g., 50.0 rather than 50), got {cell_percentage!r} of type {type(cell_percentage).__name__}") if not (0.0 <= cell_percentage <= 100.0): raise PyRatException(f"Argument 'cell_percentage' must be a percentage between 0.0 and 100.0, got {cell_percentage!r}") # Protected attributes # They must be set before calling the parent constructor, which generates the maze self._cell_percentage = cell_percentage # Inherit from parent class super().__init__(*args, **kwargs)
################################################################################## # PROTECTED METHODS # ################################################################################## def _add_cells (self) -> None: """ *(This method redefines the method of the parent class with the same name).* It adds cells to the maze by growing it from its center, adding neighbors of already added cells in a random order. Contrary to the parent class, it does not start from a full maze, so missing cells end up on the sides. """ # Determine the number of cells to keep self._target_nb_vertices = int(self.get_width() * self.get_height() * self._cell_percentage / 100) if not (self._target_nb_vertices > 1): raise PyRatException(f"The maze must have at least two vertices, got {self._target_nb_vertices!r} cell(s) to keep ({self._cell_percentage!r}% of a {self.get_width()}x{self.get_height()} grid): increase 'cell_percentage' or the maze size") # Add cells from the middle of the maze vertices_to_add = [self.rc_to_i(self.get_height() // 2, self.get_width() // 2)] # Make some sort of breadth-first search to add cells while self.nb_vertices() < self._target_nb_vertices: # Get a random vertex vertex = vertices_to_add.pop(self._rng.randint(0, len(vertices_to_add) - 1)) # Add it if it is not already in the maze if vertex in self.get_vertices(): continue self.add_vertex(vertex) # Add neighbors row, col = self.i_to_rc(vertex) if 0 < row < self.get_height(): vertices_to_add.append(self.rc_to_i(row - 1, col)) if 0 <= row < self.get_height() - 1: vertices_to_add.append(self.rc_to_i(row + 1, col)) if 0 < col < self.get_width(): vertices_to_add.append(self.rc_to_i(row, col - 1)) if 0 <= col < self.get_width() - 1: vertices_to_add.append(self.rc_to_i(row, col + 1)) # Connect the vertices for i, vertex_1 in enumerate(self.get_vertices()): for j, vertex_2 in enumerate(self.get_vertices(), i + 1): if self.coords_difference(vertex_1, vertex_2) in [(0, 1), (1, 0), (-1, 0), (0, -1)]: self.add_edge(vertex_1, vertex_2)
########################################################################################## ##########################################################################################