def render(self, grid: Grid, **kwargs: Any) -> None: horizontal_wall = "\u2501" vertical_wall = "\u2503" output = self.JUNCTIONS[12] for x in range(grid.columns - 1): output += (horizontal_wall * 3 + self.get_topmost_junction( cast(Cell, grid.cell_at(row=0, column=x)))) output += horizontal_wall * 3 + self.JUNCTIONS[10] + "\n" for row in grid.each_row(): top = vertical_wall bottom = self.get_leftmost_junction(row[0]) for cell in row: body = grid.contents_of(cell) east_boundary = " " if cell.linked_to( cell.east) else vertical_wall top += body + east_boundary south_boundary = " " if cell.linked_to( cell.south) else horizontal_wall * 3 bottom += south_boundary + self.get_south_east_junction(cell) output += top + "\n" output += bottom + "\n" print(output)
def test_random_cell() -> None: grid = Grid(2, 2) for _ in range(100): assert grid.random_cell() in [ Cell(0, 0), Cell(0, 1), Cell(1, 0), Cell(1, 1) ]
def test_constructor() -> None: grid = Grid(2, 2) assert grid.columns == 2 assert grid.rows == 2 grid = Grid(3, 3) assert grid.columns == 3 assert grid.rows == 3
def test_constructor() -> None: grid = Grid(1, 1) assert grid.columns == 1 assert grid.rows == 1 grid = Grid(2, 2) assert grid.columns == 2 assert grid.rows == 2
def on(self, grid: Grid) -> None: if self.starting_cell is None: self.starting_cell = grid.random_cell() if not is_cell(self.starting_cell) or self.starting_cell not in grid: ValueError( "Starting point of the algorithm must be a valid cell in the grid" ) # We'll use the list as a stack to do very easily any backtracking walked_path = [] walked_path.append(self.starting_cell) while len(walked_path) > 0: current_cell = walked_path[-1] unvisited_neighbors = [ neighbor for neighbor in current_cell.neighbors if len(neighbor.links) == 0 ] if len(unvisited_neighbors) == 0: walked_path.pop() else: neighbor = choice(unvisited_neighbors) current_cell += neighbor walked_path.append(neighbor)
def on(self, grid: Grid) -> None: if self.start is None: start = grid.randomCell() elif isCell(start) and start in grid: start = start else: ValueError( 'The starting point of the algorithm must be a cell in the grid' ) # We'll use the list as a stack to do any backtracking walked_path = [] walked_path.append(start) while len(walked_path) > 0: current_cell = walked_path[-1] unvisited_neighbours = [ n for n in current_cell.neighbours if n.nLinks == 0 ] if len(unvisited_neighbours) == 0: walked_path.pop() else: neighbour = choice(unvisited_neighbours) current_cell += neighbour walked_path.append(neighbour) self.step()
def _render(grid: Grid, cell_size: int = 4, coloring: bool = False) -> Image: wall_color = (0, 0, 0) image_width = cell_size * grid.columns image_height = cell_size * grid.rows image = Image.new("RGBA", (image_width + 1, image_height + 1), (255, 255, 255)) draw = ImageDraw.Draw(image) for draw_pass in range(2): for cell in grid.each_cell(): x1 = cell.column * cell_size y1 = cell.row * cell_size x2 = (cell.column + 1) * cell_size y2 = (cell.row + 1) * cell_size if draw_pass == STEP_BACKGROUND and coloring: if coloring: color = cast(ColoredGrid, grid).background_color_for(cell) else: color = (255, 255, 255) draw.rectangle((x1, y1, x2, y2), fill=color) else: if not cell.north: draw.line((x1, y1, x2, y1), fill=wall_color, width=1) if not cell.west: draw.line((x1, y1, x1, y2), fill=wall_color, width=1) if not cell.linked_to(cell.east): draw.line((x2, y1, x2, y2), fill=wall_color, width=1) if not cell.linked_to(cell.south): draw.line((x1, y2, x2, y2), fill=wall_color, width=1) return image
def on(self, grid: Grid) -> None: unvisited = [] for cell in grid.eachCell(): unvisited.append(cell) first_cell = choice(unvisited) unvisited.remove(first_cell) while len(unvisited) > 0: # start a walk cell = choice(unvisited) path = [cell] while cell in unvisited: cell = cell.randomNeighbour() # type: ignore try: position = path.index(cell) # already walked, perform loop-erase. e.g. 'A -> B -> C -> D -> B' becomes 'A -> B' path = path[:position + 1] except ValueError: path.append(cell) self.step() # Passage carving once has found a valid path for index in range(len(path) - 1): path[index] += (path[index + 1]) unvisited.remove(path[index]) self.step()
def on(grid: Grid) -> Grid: unvisited = [] for cell in grid.each_cell(): unvisited.append(cell) first_cell = choice(unvisited) unvisited.remove(first_cell) while len(unvisited) > 0: # start a walk cell = choice(unvisited) path = [cell] while cell in unvisited: cell = choice(cell.neighbors) try: position = path.index(cell) # already walked, perform loop-erase. e.g. A -> B -> C -> D -> B becomes A -> B path = path[:position + 1] except ValueError: path.append(cell) # Passage carving once has found a valid path for index in range(len(path) - 1): path[index].link(path[index + 1]) unvisited.remove(path[index]) return grid
def render(self, grid: Grid, **kwargs: Any) -> None: output = '+' + '---+' * grid.cols + '\n' for row in grid.eachRow(): top = '|' bottom = '+' for cell in row: # NOTE: Book here creates dummy (-1,-1) cell. Not doing it until needed body = grid.contents(cell) east_boundary = ' ' if cell & cell.east else '|' top += body + east_boundary south_boundary = ' ' if cell & cell.south else '---' corner = '+' bottom += south_boundary + corner output += top + '\n' output += bottom + '\n' print(output)
def _rotate_cell_neighbors(new_cell: Cell, old_cell: Cell, grid: Grid) -> None: for link in old_cell.links: row, column = Rotator._rotated_coordinates(link, grid) neighbor = grid.cell_at(row, column) if neighbor is None: raise IndexError("Cell not found at row {} column {}".format( row, column)) new_cell.link(neighbor)
def _prepareLogGrid(self, grid: Grid) -> None: ''' Prepare the grid for logging the algorithm ''' if not self.log: return # 'visit' : List of steps on which the cell was visited # 'links' : Directions of the links made by the cell (NOT to the cell) data = {'visit': [], 'links': []} # type: Dict key = self.name # type: str for cell in grid.eachCell(): cell.data[key] = data
def render(self, grid: Grid, **kwargs: Any) -> None: output = "+" + "---+" * grid.columns + "\n" for row in grid.each_row(): top = "|" bottom = "+" for cell in row: # NOTE: Book here creates dummy (-1,-1) cell. Not doing it until needed body = grid.contents_of(cell) east_boundary = " " if cell.linked_to(cell.east) else "|" top += body + east_boundary south_boundary = " " if cell.linked_to(cell.south) else "---" corner = "+" bottom += south_boundary + corner output += top + "\n" output += bottom + "\n" print(output)
def on(self, grid: Grid) -> None: for cell in grid.each_cell(): neighbors = [] if cell.north: neighbors.append(cell.north) if cell.east: neighbors.append(cell.east) if len(neighbors) > 0: neighbor = choice(neighbors) cell += neighbor
def on(grid: Grid) -> Grid: for cell in grid.each_cell(): neighbors = [] if cell.north: neighbors.append(cell.north) if cell.east: neighbors.append(cell.east) if len(neighbors) > 0: cell.link(choice(neighbors)) return grid
def on(self, grid: Grid) -> None: current_cell = grid.random_cell() unvisited_count = grid.size - 1 while unvisited_count > 0: neighbor = current_cell.random_neighbour() if neighbor is None: raise ValueError("Aldous-Broder algorithm needs all cells to have at least one neighbor") if len(neighbor.links) == 0: current_cell += neighbor unvisited_count -= 1 current_cell = neighbor
def on(self, grid: Grid) -> None: current_cell: Optional[Cell] = grid.random_cell() while current_cell is not None: unvisited_neighbors = [neighbor for neighbor in current_cell.neighbors if len(neighbor.links) == 0] if len(unvisited_neighbors) > 0: # as int as there are unvisited paths, walk them neighbor = choice(unvisited_neighbors) current_cell += neighbor current_cell = neighbor else: # enter hunt mode, find first unvisited cell near any visited cell current_cell = None for cell in grid.each_cell(): visited_neighbors = [neighbor for neighbor in cell.neighbors if len(neighbor.links) > 0] if len(cell.links) == 0 and len(visited_neighbors) > 0: current_cell = cast(Cell, cell) # outside of Mypy it's a mere assignment neighbor = choice(visited_neighbors) current_cell += neighbor break
def test_cell_access_using_operator_overloads() -> None: grid = Grid(2, 2) assert grid[0, 0] == Cell(0, 0) assert grid[0, 1] == Cell(0, 1) assert grid[1, 0] == Cell(1, 0) assert grid[1, 1] == Cell(1, 1) assert grid[-1, 0] is None assert grid[0, -1] is None assert grid[4, 0] is None assert grid[0, 4] is None
def _render(grid: Grid, cell_size: int=4, coloring: bool=False) -> Image: ''' Rendering core ''' wall_color = (0, 0, 0) image = Image.new('RGBA', (cell_size * grid.cols + 1, cell_size * grid.rows + 1), (255, 255, 255)) draw = ImageDraw.Draw(image) for draw_pass in range(2): for cell in grid.eachCell(): x1 = cell.col * cell_size y1 = cell.row * cell_size x2 = (cell.col + 1) * cell_size y2 = (cell.row + 1) * cell_size if draw_pass == 0: color = grid.color(cell) if coloring else (255, 255, 255) # type: ignore draw.rectangle((x1, y1, x2, y2), fill=color) else: if not cell.north: draw.line((x1, y1, x2, y1), fill=wall_color, width=1) if not cell.west: draw.line((x1, y1, x1, y2), fill=wall_color, width=1) if not cell & cell.east: draw.line((x2, y1, x2, y2), fill=wall_color, width=1) if not cell & cell.south: draw.line((x1, y2, x2, y2), fill=wall_color, width=1) return image
def test_neighbors_setup_when_grid_is_created() -> None: grid = Grid(2, 2) assert grid.get_cell(0, 0).north is None # type: ignore assert grid.get_cell(0, 0).south == Cell(1, 0) # type: ignore assert grid.get_cell(0, 0).east == Cell(0, 1) # type: ignore assert grid.get_cell(0, 0).west is None # type: ignore assert grid.get_cell(0, 1).north is None # type: ignore assert grid.get_cell(0, 1).south == Cell(1, 1) # type: ignore assert grid.get_cell(0, 1).east is None # type: ignore assert grid.get_cell(0, 1).west == Cell(0, 0) # type: ignore assert grid.get_cell(1, 0).north == Cell(0, 0) # type: ignore assert grid.get_cell(1, 0).south is None # type: ignore assert grid.get_cell(1, 0).east == Cell(1, 1) # type: ignore assert grid.get_cell(1, 0).west is None # type: ignore assert grid.get_cell(1, 1).north == Cell(0, 1) # type: ignore assert grid.get_cell(1, 1).south is None # type: ignore assert grid.get_cell(1, 1).east is None # type: ignore assert grid.get_cell(1, 1).west == Cell(1, 0) # type: ignore
def render(self, grid: Grid, **kwargs: Any) -> None: horizontal_wall = '\u2501' vertical_wall = '\u2503' output = self.JUNCTIONS[12] for x in range(grid.cols - 1): output += (horizontal_wall * 3 + self.get_topmost_junction(cast(Cell, grid[0, x]))) output += horizontal_wall * 3 + self.JUNCTIONS[10] + '\n' for row in grid.eachRow(): top = vertical_wall bottom = self.get_leftmost_junction(row[0]) for cell in row: body = grid.contents(cell) east_boundary = ' ' if cell & cell.east else vertical_wall top += body + east_boundary south_boundary = ' ' if cell & cell.south else horizontal_wall * 3 bottom += south_boundary + self.get_south_east_junction(cell) output += top + '\n' output += bottom + '\n' print(output)
def on(self, grid: Grid) -> Grid: grid_type = type(grid) # row i becomes col n-i when rotating 90 degrees clockwise rotated_grid = grid_type(rows=grid.cols, cols=grid.rows) for old_cell in grid.eachCell(): row, column = self._rotated_coordinates(old_cell, rotated_grid) new_cell = rotated_grid[row, column] if new_cell is None: raise IndexError('Cell not found at row {} column {}'.format( row, column)) self._rotate_cell_neighbors(new_cell, old_cell, rotated_grid) return rotated_grid
def on(grid: Grid) -> Grid: current_cell = grid.random_cell() # type: Optional[Cell] while current_cell is not None: unvisited_neighbors = \ [neighbor for neighbor in current_cell.neighbors if len(neighbor.links) == 0] if len(unvisited_neighbors) > 0: # as long as there are unvisited paths, walk them neighbor = choice(unvisited_neighbors) current_cell.link(neighbor) current_cell = neighbor else: # enter hunt mode, find first unvisited cell near any visited cell current_cell = None for cell in grid.each_cell(): visited_neighbors = [neighbor for neighbor in cell.neighbors if len(neighbor.links) > 0] if len(cell.links) == 0 and len(visited_neighbors) > 0: current_cell = cast(Cell, cell) neighbor = choice(visited_neighbors) current_cell.link(neighbor) break return grid
def on(self, grid: Grid) -> None: for row in grid.eachRow(): run = [] for cell in row: run.append(cell) at_eastern_boundary = cell.east is None at_northen_boundary = cell.north is None should_close_out = at_eastern_boundary or (not at_northen_boundary and randint(0, 1) == 0) if should_close_out: member = choice(run) if member.north: member += member.north run.clear() else: cell += cell.east # type: ignore # Made sure cell is not at eastern boundry self.step()
def on(grid: Grid) -> Grid: current_cell = grid.random_cell() unvisited_count = grid.size - 1 while unvisited_count > 0: neighbor = choice(current_cell.neighbors) if neighbor is None: raise ValueError( "Aldous-Broder algorithm needs all cells to have at least one neighbor" ) if len(neighbor.links) == 0: current_cell.link(neighbor) unvisited_count -= 1 current_cell = neighbor return grid
def on(self, grid: Grid) -> None: self._prepareLogGrid(grid) for cell in grid.eachCell(): self._logVisit(cell) neighbours = [] if cell.north: neighbours.append(cell.north) if cell.east: neighbours.append(cell.east) if len(neighbours) > 0: neighbour = choice(neighbours) cell += neighbour self._logLink(cell, neighbour) self.step()
def on(self, grid: Grid) -> None: for row in grid.each_row(): run = [] for cell in row: run.append(cell) at_eastern_boundary = cell.east is None at_northen_boundary = cell.north is None should_close_out = at_eastern_boundary or (not at_northen_boundary and randint(0, 1) == 0) if should_close_out: member = choice(run) if member.north: member += member.north run.clear() else: cell += cast(Cell, cell.east)
def on(grid: Grid) -> Grid: for row in grid.each_row(): run = [] for cell in row: run.append(cell) at_eastern_boundary = cell.east is None at_northen_boundary = cell.north is None should_close_out = at_eastern_boundary or ( not at_northen_boundary and randint(0, 1) == 0) if should_close_out: member = choice(run) if member.north: member.link(member.north) run.clear() else: cell.link(cell.east) return grid
def test_cell_access() -> None: grid = Grid(2, 2) assert grid.cell_at(0, 0) == Cell(0, 0) assert grid.cell_at(0, 1) == Cell(0, 1) assert grid.cell_at(1, 0) == Cell(1, 0) assert grid.cell_at(1, 1) == Cell(1, 1) assert grid.cell_at(-1, 0) is None assert grid.cell_at(0, -1) is None assert grid.cell_at(4, 0) is None assert grid.cell_at(0, 4) is None
def test_cell_access() -> None: grid = Grid(2, 2) assert grid.get_cell(0, 0) == Cell(0, 0) # type: ignore assert grid.get_cell(0, 1) == Cell(0, 1) # type: ignore assert grid.get_cell(1, 0) == Cell(1, 0) # type: ignore assert grid.get_cell(1, 1) == Cell(1, 1) # type: ignore assert grid.get_cell(-1, 0) is None assert grid.get_cell(0, -1) is None assert grid.get_cell(4, 0) is None assert grid.get_cell(0, 4) is None