'Python Object suddenly went Empty and all attributs are False

import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"

import pygame
import random
from abc import abstractmethod

class Cell:
    NUMBER_OF_CELLS = 0

    def __init__(self):
        self.id = Cell.NUMBER_OF_CELLS
        Cell.NUMBER_OF_CELLS += 1

        self.top_cell = None
        self.bottom_cell = None
        self.left_cell = None
        self.right_cell = None
        self.top_wall = True
        self.bottom_wall = True
        self.left_wall = True
        self.right_wall = True

        self.visited = False

    def set_visited(self, visited: bool) -> None:
        """Sets the visited status of the cell

        Args:
            visited (bool): The visited status to set
        """
        self.visited = visited

    def has_unvisited_neighbors(self) -> bool:
        """Check if all neighbors are visited or not

        Returns:
            bool: True if there is at least one, else False
        """
        return (
            self.top_cell is not None
            and not self.top_cell.visited
            or self.bottom_cell is not None
            and not self.bottom_cell.visited
            or self.left_cell is not None
            and not self.left_cell.visited
            or self.right_cell is not None
            and not self.right_cell.visited
        )

    def get_unvisited_neighbors(self) -> list["Cell"]:
        """Get all univisited neighbors of the cell (top, bottom, left and right)

        Returns:
            list["Cell"]: List of unvisited neighbors (cells)
        """
        neighbors = []
        if self.top_cell is not None and not self.top_cell.visited:
            neighbors.append(self.top_cell)
        if self.bottom_cell is not None and not self.bottom_cell.visited:
            neighbors.append(self.bottom_cell)
        if self.left_cell is not None and not self.left_cell.visited:
            neighbors.append(self.left_cell)
        if self.right_cell is not None and not self.right_cell.visited:
            neighbors.append(self.right_cell)
        return neighbors

    def open_wall_with(self, cell: "Cell") -> None:
        """Opens the wall in the given direction for both cells (method called and parameter one)

        Args:
            cell (Cell): The cell to open the wall with
        """
        direction = self.get_direction(cell)
        if direction == "top":
            self.top_wall = False
            self.top_cell.bottom_wall = False
        elif direction == "bottom":
            self.bottom_wall = False
            self.bottom_cell.top_wall = False
        elif direction == "left":
            self.left_wall = False
            self.left_cell.right_wall = False
        elif direction == "right":
            self.right_wall = False
            self.right_cell.left_wall = False

    def get_direction(self, cell: "Cell") -> str:
        """Gets the direction to the given cell from this cell

        Args:
            cell (Cell): The cell to get the direction to

        Returns:
            str: The direction to the given cell or empty string if not found
        """
        if self.top_cell is cell:
            return "top"
        elif self.bottom_cell is cell:
            return "bottom"
        elif self.left_cell is cell:
            return "left"
        elif self.right_cell is cell:
            return "right"
        else:
            return ""
    
    def __str__(self):
        tmp = ""
        tmp += "1" if self.top_wall else "0"
        tmp += "1" if self.bottom_wall else "0"
        tmp += "1" if self.left_wall else "0"
        tmp += "1" if self.right_wall else "0"
        return f" {tmp} "


class Maze:
    def __init__(self, width: int, height: int):
        self.width = width
        self.height = height
        self.cells = [[Cell() for _ in range(height)] for _ in range(width)]
        self.link_cells()

    def __str__(self):
        s = ""
        for i in range(self.height):
            for j in range(self.width):
                s += str(self.cells[j][i])
            s += "\n"
        return s

    def link_cells(self) -> None:
        """Links all cells recursively"""
        for i in range(self.width):
            for j in range(self.height):
                cell = self.cells[i][j]
                if j > 0:
                    cell.top_cell = self.cells[i][j - 1]
                if j < self.height - 1:
                    cell.bottom_cell = self.cells[i][j + 1]
                if i > 0:
                    cell.left_cell = self.cells[i - 1][j]
                if i < self.width - 1:
                    cell.right_cell = self.cells[i + 1][j]


class MazeBuilder:
    ALGORITHMS = []

    def __init__(self, num: int):

        MazeBuilder.ALGORITHMS = [
            method_name
            for method_name in dir(self)
            if callable(getattr(self, method_name)) and not method_name.startswith("__")
            and method_name != "build"
        ]

        self.algorithm = MazeBuilder.ALGORITHMS[num]

    def build(self, maze: Maze) -> None:
        self.algorithm(maze)

    @staticmethod
    def depth_first_search(maze: Maze) -> None:
        """Depth First Search algorithm (iterative, cuz the recursive one overflows the stack)

        Args:
            maze (Maze): An untouched maze object to be built upon
        """
        maze.cells[0][0].set_visited(True)
        stack = [maze.cells[0][0]]
        while len(stack) != 0:
            current_cell = stack.pop()
            if current_cell.has_unvisited_neighbors():
                stack.append(current_cell)
                chosen_cell = random.choice(current_cell.get_unvisited_neighbors())
                current_cell.open_wall_with(chosen_cell)
                chosen_cell.set_visited(True)
                stack.append(chosen_cell)


class MazeSolver:
    ALGORITHMS = []
    
    def __init__(self, num: int):
        
        MazeSolver.ALGORITHMS = [
            method_name
            for method_name in dir(self)
            if callable(getattr(self, method_name)) and not method_name.startswith("__")
            and method_name != "solve"
        ]

        
        self.algorithm = MazeSolver.ALGORITHMS[num]
        
    def solve(self, maze: Maze) -> None:
        self.algorithm(maze)
        
    @staticmethod
    def a_star(maze: Maze) -> None:
        """Depth First Search algorithm (iterative, cuz the recursive one overflows the stack)

        Args:
            maze (Maze): An untouched maze object to be built upon
        """
        pass

class Color:
    WHITE = pygame.Color("white")
    BLACK = pygame.Color("black")
    RED = pygame.Color("red")
    BLUE =  pygame.Color("blue")

class Window:
    FPS = 60
    WIDTH = 1280
    HEIGHT = 720
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((Window.WIDTH, Window.HEIGHT))
        self.screen.fill(Color.WHITE)
        pygame.display.set_caption("MazeBuild&Solve")
        self.run = False
        self.clock = pygame.time.Clock()
    
    @abstractmethod
    def start(self):
        raise NotImplementedError("Not implemented abstract method for object type 'Window'")
        

class MazeDrawer(Window):
    def __init__(self, alg_gen: int, alg_sol: int, width: int, height: int):
        super().__init__()
        self.maze_builder = MazeBuilder(alg_gen)
        self.maze_solver = MazeSolver(alg_sol)
        self.maze = Maze(width, height)
        
    def _draw_line(self, start_coords: tuple, end_coords: tuple):
        pygame.draw.line(self.screen, Color.BLACK, start_coords, end_coords)
    
    def _draw_maze(self) -> None:
        """Draw the maze on pygame's window"""
        pass 
                
    def start(self):
        self.run = True
        while self.run:
            
            # Setting the tick to Window.FPS (default: 60)
            self.clock.tick(Window.FPS)
            
            # Looking for any event
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.run = False
            
            self._draw_maze()

            pygame.display.update()
            pygame.display.flip()

def main():
    _ = MazeBuilder(0)  # Needed to init the MazeBuilder.ALGORITHMS list
    _ = MazeSolver(0)  # Needed to init the MazeSolver.ALGORITHMS list
    
    alg_gen, alg_sol, width, height = -1, -1, -1, -1
    
    for i in range(len(MazeBuilder.ALGORITHMS)):
        print(f"{i}: {MazeBuilder.ALGORITHMS[i]}")
        
    print()
    
    while(alg_gen := int(input("Input the n° of the algorithm for the generation: ")) not in range(len(MazeBuilder.ALGORITHMS))):
        continue
    
    print()
    
    for i in range(len(MazeSolver.ALGORITHMS)):
        print(f"{i}: {MazeSolver.ALGORITHMS[i]}")
        
    print()
    
    while(alg_sol := int(input("Input the n° of the algorithm for the solving: ")) not in range(len(MazeSolver.ALGORITHMS))):
        continue
    
    print()
    
    while(width := int(input("Width of the maze: \t")) not in range(1000)):
        continue
    
    print()
    
    while(height := int(input("Height of the maze: \t")) not in range(1000)):
        continue
    
    m = MazeDrawer(alg_gen, alg_sol, width, height)
    print(m.maze)
    m.start()

if __name__ == "__main__":
    main()

I'm having trouble with the last instruction of my code. Well, I don't understand why, but my print(m.maze) function prints me nothing and all attributs of the maze are False. What is happening? I tried everything but I couldn't find the issue.

As you might have noticed, I'm doing a maze builder and solver. However, when the Maze object is created from the user's input, the maze goes empty for no reason...



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source