O construtor
Antes de abrir qualquer parede, o Maze (a grade de paredes, da
página anterior) precisa existir: saber o tamanho da grade, saber
quais células desenham o "42" e criar todas as células com as quatro paredes fechadas, o valor
ALL_WALLS = 15. Esta página escreve o construtor, __init__, e começa o arquivo
mazegen/entities/maze.py.
def __init__(self, width: int, height: int, pattern: Pattern42) -> None:
self.width = width
self.height = height
self.pattern = pattern
self._walls: list[list[int]] = [
[ALL_WALLS] * width for _ in range(height)
]
width,heightepatternficam públicos: os algoritmos leem o tamanho da grade e as células do "42" (oPattern42, construído na parte 4)._wallsé a grade: uma lista com uma lista por linha, cada uma comwidthnúmeros. A anotaçãolist[list[int]]diz isso ao mypy: uma lista de listas de inteiros._walls[y][x]são as paredes da célulax,y: primeiro se escolhe a linha (y), depois a coluna (x). É a mesma ordem do arquivo de saída, linha por linha.-> Nonediz que o construtor não devolve nada.
O Maze recebe o Pattern42 pronto, em vez de calculá-lo. Quem cria o Maze (o
MazeGenerator, parte 9) já calculou o padrão antes, para
conferir que a entrada e a saída não caem no "42", e o mesmo objeto serve aos dois.
Um Maze 3x2 recém-criado, com o valor de cada célula (as linhas grossas são paredes
fechadas):
O _ de _walls
O sublinhado no começo do nome é a convenção do Python para "interno: não mexa de fora". Os
algoritmos não escrevem em _walls diretamente. Eles leem com walls(cell) e mudam com
open_wall e close_wall, os únicos métodos que alteram a grade. É assim que a classe garante
as regras: todo caminho de mudança passa por código que as confere.
Uma lista nova por linha
[ALL_WALLS] * width cria uma lista com width cópias de 15. A forma curta para a grade toda,
[[ALL_WALLS] * width] * height, parece igual, mas está errada: o * height repete a mesma
lista height vezes. Mudar uma linha muda todas:
rows = [[15] * 3] * 2
rows[0][0] = 13
print(rows)
rows = [[15] * 3 for _ in range(2)]
rows[0][0] = 13
print(rows)
[[13, 15, 15], [13, 15, 15]]
[[13, 15, 15], [15, 15, 15]]
Na primeira forma, mudar a célula 0,0 mudou também a 0,1. A versão com
for _ in range(height) cria uma lista nova a cada volta. O _ é o nome que se dá a uma
variável que não é usada: só importa repetir height vezes.
Essa forma, com um for dentro dos colchetes, se chama compreensão de lista (list
comprehension): ela monta uma lista calculando a expressão da esquerda ([15] * 3) a cada
volta do for. Equivale a começar com uma lista vazia e fazer um append por volta.
Dentro de uma linha, [ALL_WALLS] * width não tem esse problema: os elementos são inteiros, e um
inteiro não muda, só é trocado por outro.
O começo do arquivo
O Maze é construído aos poucos, ao longo desta parte, num único arquivo. Crie agora
mazegen/entities/maze.py com o que esta página mostrou:
"""Mutable grid of wall masks, the state the generator carves."""
from mazegen.value_objects.pattern42 import Pattern42
ALL_WALLS = 15
class Maze:
def __init__(self, width: int, height: int, pattern: Pattern42) -> None:
self.width = width
self.height = height
self.pattern = pattern
self._walls: list[list[int]] = [
[ALL_WALLS] * width for _ in range(height)
]
- A primeira linha é a docstring do módulo (o texto que documenta o arquivo).
- O
importtraz oPattern42, usado na anotação do parâmetropattern.
Cada página seguinte acrescenta métodos dentro da classe Maze, depois dos que já estão lá,
com a mesma indentação do __init__ (4 espaços). Quando um método novo precisa de algo de outro
arquivo, a página mostra o import que entra no topo. A última página desta parte,
A cópia da grade, termina com o arquivo completo: o mesmo que se
monta aqui, mais as docstrings de cada método.
Experimente
Com o arquivo acima gravado, na raiz do projeto (a página Como rodar os exemplos explica o formato):
.venv/bin/python - <<'EOF'
from mazegen.entities.maze import Maze
from mazegen.value_objects.pattern42 import Pattern42
maze = Maze(9, 7, Pattern42.for_size(9, 7))
print(maze.width, maze.height, len(maze.pattern.cells))
EOF
9 7 18
Uma grade de 9 colunas por 7 linhas, com as 18 células do "42".