Dan Anglin
4c7e50ec39
Add a side panel to allow users to interact with the app. The generate button now generates the maze.
159 lines
4.4 KiB
Python
159 lines
4.4 KiB
Python
from typing import Dict
|
|
from enum import Enum
|
|
from tkinter import Canvas
|
|
from graphics import Graphics, Point, Line
|
|
import errors
|
|
|
|
|
|
class CellWallLabels(Enum):
|
|
"""
|
|
CellWallLabel is used to label a CellWall
|
|
"""
|
|
|
|
TOP = 0
|
|
BOTTOM = 1
|
|
LEFT = 2
|
|
RIGHT = 3
|
|
|
|
|
|
class CellWall:
|
|
"""
|
|
A CellWall represents the existence (or non-existence) of
|
|
a Cell's wall.
|
|
"""
|
|
|
|
def __init__(self, line: Line, graphics: Graphics) -> None:
|
|
self.exists = True
|
|
self.line = line
|
|
self._graphics = graphics
|
|
|
|
def draw(self):
|
|
fill_colour = "black"
|
|
if not self.exists:
|
|
fill_colour = "white"
|
|
|
|
self._graphics.draw_line(self.line, fill_colour=fill_colour)
|
|
|
|
|
|
class Cell:
|
|
"""
|
|
A Cell represents a grid on the maze.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
x1: int, y1: int,
|
|
x2: int, y2: int,
|
|
graphics: Graphics = None,
|
|
) -> None:
|
|
# Validation
|
|
if (x2 < x1) or (y2 < y1):
|
|
raise errors.CellInvalidError(x1, y1, x2, y2)
|
|
|
|
if (x2 - x1) < 2:
|
|
raise errors.CellTooSmallError("horizontal", x2-x1)
|
|
|
|
if (y2 - y1) < 2:
|
|
raise errors.CellTooSmallError("vertical", y2-y1)
|
|
|
|
# Define the cell walls
|
|
top_wall = Line(Point(x1, y1), Point(x2, y1))
|
|
bottom_wall = Line(Point(x1, y2), Point(x2, y2))
|
|
left_wall = Line(Point(x1, y1), Point(x1, y2))
|
|
right_wall = Line(Point(x2, y1), Point(x2, y2))
|
|
|
|
self._walls: Dict[CellWallLabels, CellWall] = {
|
|
CellWallLabels.TOP: CellWall(top_wall, graphics),
|
|
CellWallLabels.BOTTOM: CellWall(bottom_wall, graphics),
|
|
CellWallLabels.LEFT: CellWall(left_wall, graphics),
|
|
CellWallLabels.RIGHT: CellWall(right_wall, graphics),
|
|
}
|
|
|
|
# Calculate the cell's central point
|
|
centre_x = x1 + ((x2 - x1) / 2)
|
|
centre_y = y1 + ((y2 - y1) / 2)
|
|
self._centre = Point(centre_x, centre_y)
|
|
|
|
self._graphics = graphics
|
|
|
|
self._visited: Dict[str, bool] = {
|
|
"generator": False,
|
|
"solver": False,
|
|
}
|
|
|
|
def configure_walls(
|
|
self,
|
|
top: bool = None,
|
|
bottom: bool = None,
|
|
left: bool = None,
|
|
right: bool = None,
|
|
) -> None:
|
|
"""
|
|
configure_walls configures the existence of the Cell's walls.
|
|
"""
|
|
if top is not None:
|
|
self._walls[CellWallLabels.TOP].exists = top
|
|
if bottom is not None:
|
|
self._walls[CellWallLabels.BOTTOM].exists = bottom
|
|
if left is not None:
|
|
self._walls[CellWallLabels.LEFT].exists = left
|
|
if right is not None:
|
|
self._walls[CellWallLabels.RIGHT].exists = right
|
|
|
|
def centre(self) -> Point:
|
|
"""
|
|
centre returns the Cell's central point
|
|
"""
|
|
return self._centre
|
|
|
|
def wall_exists(self, wall: CellWallLabels) -> bool:
|
|
"""
|
|
returns True if a given cell wall exists, or false otherwise.
|
|
"""
|
|
if wall not in CellWallLabels:
|
|
raise TypeError(
|
|
"The argument does not appear to be a valid cell wall."
|
|
)
|
|
return self._walls[wall].exists
|
|
|
|
def draw(self) -> None:
|
|
"""
|
|
draw draws the cell onto the canvas
|
|
"""
|
|
if not self._graphics:
|
|
return
|
|
|
|
for label in CellWallLabels:
|
|
self._walls[label].draw()
|
|
|
|
def draw_move(self, to_cell: 'Cell', undo: bool = False) -> None:
|
|
"""
|
|
draw_move draws a path between the centre of this cell and
|
|
the centre of the given cell.
|
|
"""
|
|
if not self._graphics:
|
|
return
|
|
|
|
fill_colour = "red"
|
|
if undo:
|
|
fill_colour = "grey"
|
|
line = Line(self.centre(), to_cell.centre())
|
|
self._graphics.draw_line(line, fill_colour)
|
|
|
|
def was_visited_by(self, visitor: str) -> bool:
|
|
"""
|
|
returns True if the cell was visited by the
|
|
specified visitor.
|
|
"""
|
|
if visitor not in ("solver", "generator"):
|
|
raise ValueError(f"This is an unknown visitor ({visitor})")
|
|
|
|
return self._visited[visitor]
|
|
|
|
def mark_as_visited_by(self, visitor: str) -> None:
|
|
"""
|
|
marks the cell as visited by the specified visitor.
|
|
"""
|
|
if visitor not in ("solver", "generator"):
|
|
raise ValueError(f"This is an unknown visitor ({visitor})")
|
|
self._visited[visitor] = True
|