Home > Blockchain >  Python Object suddenly went Empty and all attributs are False
Python Object suddenly went Empty and all attributs are False

Time:02-28

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...

CodePudding user response:

Your big problem is parentheses:

    while(alg_gen := int(input("Input the n° of the algorithm for the generation: ")) not in range(len(MazeBuilder.ALGORITHMS))):

Because of the way you have written it, alg_gen is going to be assigned the result of the not in expression, which is False. Thus, what you're passing to the Maze constructor is FalsexFalse, and it happily creates a 0x0 maze.

You need:

    while((alg_gen := int(input("Input the n° of the algorithm for the generation: "))) not in range(len(MazeBuilder.ALGORITHMS))):

and the same in the rest of the inputs. That's the danger with getting too clever. This probably would be clearer without the walrus:

    while True:
        alg_gen = int(input(...))
        if alg_gen in range(len(MazeBuilder.ALGORITHMS)):
            break
  • Related