Compare commits

..

No commits in common. "609ae4fae9ae81b2082574b9db443e3ba525c3d1" and "79d972727344aad46a5a9e29522026677ce8c1a0" have entirely different histories.

4 changed files with 84 additions and 92 deletions

102
cell.py
View file

@ -1,18 +1,5 @@
from typing import Dict from typing import Dict
from enum import Enum
from graphics import Window, Point, Line from graphics import Window, Point, Line
import errors
class CellWallLabel(Enum):
"""
CellWallLabel is used to label a CellWall
"""
TOP = 0
BOTTOM = 1
LEFT = 2
RIGHT = 3
class CellWall: class CellWall:
@ -39,6 +26,11 @@ class Cell:
A Cell represents a grid on the maze. A Cell represents a grid on the maze.
""" """
TOP_WALL = 0
BOTTOM_WALL = 1
LEFT_WALL = 2
RIGHT_WALL = 3
def __init__( def __init__(
self, self,
x1: int, y1: int, x1: int, y1: int,
@ -47,13 +39,13 @@ class Cell:
) -> None: ) -> None:
# Validation # Validation
if (x2 < x1) or (y2 < y1): if (x2 < x1) or (y2 < y1):
raise errors.CellInvalidError(x1, y1, x2, y2) raise CellInvalidError(x1, y1, x2, y2)
if (x2 - x1) < 2: if (x2 - x1) < 2:
raise errors.CellTooSmallError("horizontal", x2-x1) raise CellTooSmallError("horizontal", x2-x1)
if (y2 - y1) < 2: if (y2 - y1) < 2:
raise errors.CellTooSmallError("vertical", y2-y1) raise CellTooSmallError("vertical", y2-y1)
# Define the cell walls # Define the cell walls
top_wall = Line(Point(x1, y1), Point(x2, y1)) top_wall = Line(Point(x1, y1), Point(x2, y1))
@ -61,11 +53,11 @@ class Cell:
left_wall = Line(Point(x1, y1), Point(x1, y2)) left_wall = Line(Point(x1, y1), Point(x1, y2))
right_wall = Line(Point(x2, y1), Point(x2, y2)) right_wall = Line(Point(x2, y1), Point(x2, y2))
self._walls: Dict[CellWallLabel, CellWall] = { self._walls: Dict[int, CellWall] = {
CellWallLabel.TOP: CellWall(top_wall, window), Cell.TOP_WALL: CellWall(top_wall, window),
CellWallLabel.BOTTOM: CellWall(bottom_wall, window), Cell.BOTTOM_WALL: CellWall(bottom_wall, window),
CellWallLabel.LEFT: CellWall(left_wall, window), Cell.LEFT_WALL: CellWall(left_wall, window),
CellWallLabel.RIGHT: CellWall(right_wall, window), Cell.RIGHT_WALL: CellWall(right_wall, window),
} }
# Calculate the cell's central point # Calculate the cell's central point
@ -88,10 +80,10 @@ class Cell:
""" """
configure_walls configures the existence of the Cell's walls. configure_walls configures the existence of the Cell's walls.
""" """
self._walls[CellWallLabel.TOP].exists = top self._walls[Cell.TOP_WALL].exists = top
self._walls[CellWallLabel.BOTTOM].exists = bottom self._walls[Cell.BOTTOM_WALL].exists = bottom
self._walls[CellWallLabel.LEFT].exists = left self._walls[Cell.LEFT_WALL].exists = left
self._walls[CellWallLabel.RIGHT].exists = right self._walls[Cell.RIGHT_WALL].exists = right
def centre(self) -> Point: def centre(self) -> Point:
""" """
@ -99,10 +91,9 @@ class Cell:
""" """
return self._centre return self._centre
def wall_exists(self, wall: CellWallLabel) -> bool: def wall_exists(self, wall: int) -> bool:
""" if wall not in self._walls:
returns True if a given cell wall exists, or false otherwise. raise CellInvalidWallError(wall)
"""
return self._walls[wall].exists return self._walls[wall].exists
# def break_walls_r(self, i: int, j: int) -> None: # def break_walls_r(self, i: int, j: int) -> None:
@ -119,8 +110,8 @@ class Cell:
if not self._window: if not self._window:
return return
for label in CellWallLabel: for _, wall in self._walls.items():
self._walls[label].draw() wall.draw()
def draw_move(self, to_cell: 'Cell', undo: bool = False) -> None: def draw_move(self, to_cell: 'Cell', undo: bool = False) -> None:
""" """
@ -135,3 +126,52 @@ class Cell:
fill_colour = "grey" fill_colour = "grey"
line = Line(self.centre(), to_cell.centre()) line = Line(self.centre(), to_cell.centre())
self._window.draw_line(line, fill_colour) self._window.draw_line(line, fill_colour)
class CellInvalidWallError(Exception):
"""
CellInvalidWallError is raised when the program tries to specify a Cell's
Wall that does not exist.
"""
def __init__(self, wall: int, *args):
super().__init__(args)
self.wall = wall
def __str__(self):
return f"Invalid Cell Wall (wall int: {self.wall}) specified."
class CellInvalidError(Exception):
"""
CellInvalidError is raised when the program tries to create a Cell whose
values are invalid. The values are invalid when x2 is smaller than x1
and/or y2 is smaller than y1. When creating a Cell the x and y values
should always represent the top left and the bottom right corners of
the cell (i.e. x1 < x2 and y1 < y2).
"""
def __init__(self, x1: int, y1: int, x2: int, y2: int, *args):
super().__init__(args)
self.x1 = x1
self.x2 = x2
self.y1 = y1
self.y2 = y2
def __str__(self):
return f"Invalid Cell values received. Please ensure that both: x1 ({self.x1}) < x2 ({self.x2}), and y1 ({self.y1}) < y2 ({self.y2})"
class CellTooSmallError(Exception):
"""
CellTooSmallError is raised when the program tries to create a Cell
which is too small to correctly draw it's central point.
"""
def __init__(self, size_type: str, size: int, *args):
super().__init__(args)
self.size_type = size_type
self.size = size
def __str__(self):
return f"The {self.size_type} size of the cell ({self.size}) is too small."

View file

@ -1,33 +0,0 @@
class CellInvalidError(Exception):
"""
CellInvalidError is raised when the program tries to create a Cell whose
values are invalid. The values are invalid when x2 is smaller than x1
and/or y2 is smaller than y1. When creating a Cell the x and y values
should always represent the top left and the bottom right corners of
the cell (i.e. x1 < x2 and y1 < y2).
"""
def __init__(self, x1: int, y1: int, x2: int, y2: int, *args):
super().__init__(args)
self.x1 = x1
self.x2 = x2
self.y1 = y1
self.y2 = y2
def __str__(self):
return f"Invalid Cell values received. Please ensure that both: x1 ({self.x1}) < x2 ({self.x2}), and y1 ({self.y1}) < y2 ({self.y2})"
class CellTooSmallError(Exception):
"""
CellTooSmallError is raised when the program tries to create a Cell
which is too small to correctly draw it's central point.
"""
def __init__(self, size_type: str, size: int, *args):
super().__init__(args)
self.size_type = size_type
self.size = size
def __str__(self):
return f"The {self.size_type} size of the cell ({self.size}) is too small."

29
maze.py
View file

@ -39,12 +39,9 @@ class Maze:
# Create the Maze's cells # Create the Maze's cells
self._cells: List[List[Cell]] = [None for i in range(self._num_cell_rows)] self._cells: List[List[Cell]] = [None for i in range(self._num_cell_rows)]
self._create_cells() self._create_cells()
self._open_entrance_and_exit() self._break_entrance_and_exit()
def _create_cells(self) -> None: def _create_cells(self):
"""
creates all the cells and draws them.
"""
cursor_x = self._x_position cursor_x = self._x_position
cursor_y = self._y_position cursor_y = self._y_position
@ -69,32 +66,20 @@ class Maze:
if self._window: if self._window:
self._draw_cells() self._draw_cells()
def _open_entrance_and_exit(self) -> None: def _break_entrance_and_exit(self):
""" # break entrance and draw
opens the maze's entrance and exit cells by breaking their respective
walls. The entrance is located at the top left and the exit is located
at the bottom right of the maze.
"""
self._cells[0][0].configure_walls(top=False) self._cells[0][0].configure_walls(top=False)
self._cells[0][0].draw() self._cells[0][0].draw()
# break exit and draw
self._cells[self._num_cell_rows - 1][self._num_cells_per_row - 1].configure_walls(bottom=False) self._cells[self._num_cell_rows - 1][self._num_cells_per_row - 1].configure_walls(bottom=False)
self._cells[self._num_cell_rows - 1][self._num_cells_per_row - 1].draw() self._cells[self._num_cell_rows - 1][self._num_cells_per_row - 1].draw()
def _draw_cells(self) -> None: def _draw_cells(self):
"""
draws all the cells on the maze with a short pause between each cell
for animation purposes.
"""
for i in range(self._num_cell_rows): for i in range(self._num_cell_rows):
for j in range(self._num_cells_per_row): for j in range(self._num_cells_per_row):
self._cells[i][j].draw() self._cells[i][j].draw()
self._animate() self._animate()
def _animate(self) -> None: def _animate(self):
"""
redraws the application and pauses for a short period of time to
provide an animation effect.
"""
self._window.redraw() self._window.redraw()
sleep(0.05) sleep(0.05)

View file

@ -1,7 +1,7 @@
import unittest import unittest
from cell import Cell, CellWallLabel import cell
from cell import Cell
from maze import Maze from maze import Maze
import errors
class Tests(unittest.TestCase): class Tests(unittest.TestCase):
@ -57,10 +57,10 @@ class Tests(unittest.TestCase):
2, 2,
2, 2,
) )
self.assertFalse(maze._cells[0][0].wall_exists(CellWallLabel.TOP)) self.assertFalse(maze._cells[0][0].wall_exists(Cell.TOP_WALL))
self.assertFalse( self.assertFalse(
maze._cells[number_of_cell_rows - 1] maze._cells[number_of_cell_rows - 1]
[number_of_cells_per_row - 1].wall_exists(CellWallLabel.BOTTOM) [number_of_cells_per_row - 1].wall_exists(Cell.BOTTOM_WALL)
) )
def test_invalid_cell_exception(self): def test_invalid_cell_exception(self):
@ -74,7 +74,7 @@ class Tests(unittest.TestCase):
] ]
for case in cases: for case in cases:
with self.assertRaises(errors.CellInvalidError): with self.assertRaises(cell.CellInvalidError):
_ = Cell( _ = Cell(
x1=case["x1"], x1=case["x1"],
y1=case["y1"], y1=case["y1"],
@ -93,7 +93,7 @@ class Tests(unittest.TestCase):
] ]
for case in cases: for case in cases:
with self.assertRaises(errors.CellTooSmallError): with self.assertRaises(cell.CellTooSmallError):
_ = Cell( _ = Cell(
x1=case["x1"], x1=case["x1"],
y1=case["y1"], y1=case["y1"],