Compare commits
No commits in common. "609ae4fae9ae81b2082574b9db443e3ba525c3d1" and "79d972727344aad46a5a9e29522026677ce8c1a0" have entirely different histories.
609ae4fae9
...
79d9727273
4 changed files with 84 additions and 92 deletions
102
cell.py
102
cell.py
|
@ -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."
|
||||||
|
|
33
errors.py
33
errors.py
|
@ -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
29
maze.py
|
@ -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)
|
||||||
|
|
12
tests.py
12
tests.py
|
@ -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"],
|
||||||
|
|
Loading…
Reference in a new issue