Build the Maze
00:00 Building the maze. At the very core, a maze is an ordered collection of squares, which you can represent with a Python tuple. However, you’ll eventually want to augment your maze model with additional properties and methods, so it makes sense to wrap the sequence of squares in a custom class right away.
Here, you use an immutable data class again to ensure that the underlying tuple of
Square objects remains unchanged once assigned. You might be inclined to use a Python list instead of a tuple to keep your squares, but that would prevent you from caching partial results of your computations later. Python’s cache requires memoized function arguments to be hashable and therefore immutable. To avoid the extra work when looping over the squares or when accessing one of them by index, you can make your class iterable and subscriptable by implementing these two special methods.
1 to the highest index accounts for the zero-based numbering of tuple indices. Because looping is a relatively expensive operation, you cache the return values with
functools.cached_property instead of using the built-in
@property decorator. As a result, the width and height are computed only once on demand, while their subsequent invocations will return the cached value.
02:31 The benefit of calculating the maze size by hand is data consistency. If you supplied the width and height through two extra parameters in the class, then there would be no guarantee that the rows and columns would match up with the flat index.
So inferring the size from the squares avoids this potential problem. Speaking of consistency, you can also include the validation of the maze by looping over it again when it’s created to make sure that its squares have the the expected rows and columns with matching indices. To do that, you’ll leverage the special method
.__post_init__() to hook into the initialization process of the data class.
The second function iterates over the rows and columns in the maze, and this ensures that the
.column attributes of the corresponding square match up with the current row and column of the loops. Watch out for proper indentation of these functions, as they don’t belong in the class body.
This code calls
next() on a generator expression that filters the squares by their role. Because you already validated them, you can safely assume that the appropriate squares exist in the maze, and
next() won’t raise any exception.
At long last, you can finally build your first maze using the building blocks defined earlier. This maze will be needed a number of times in this course, so to save having to type it out multiple times in a REPL session, you’ll put it inside the
mazes/ directory at the top level of the project, at the same level as the
06:58 This sample maze has twelve squares with ten unique border patterns, arranged in three rows and four columns. The entrance to the maze is located in the bottom-left corner, while the exit is in the first row, slightly to the right.
08:16 Being able to visualize the final result just by looking at the code is quite a niche skill. So, on-screen you can see what the maze would look like. It may not be a masterpiece, but having a small dataset sample to work with is beneficial for several reasons. When something doesn’t work as expected, you’ll be able to spot the problem much quicker.
08:36 You’ll also have a better understanding of the underlying concepts, allowing you to debug code more efficiently. Finally, because there’s little data to process, you’ll spend a lot less time waiting for the results in your development cycle.
08:52 So far, you’ve identified the building blocks of the maze and implemented them in Python, but now you can build a maze, the next step will be to figure out how to display it in a graphical form, and that’s what you’ll be doing in the next section of the course.
Become a Member to join the conversation.