This (mini-)assignment 2 is much smaller in scope compared to assignment 1, which required a good deal of work.
This assignment will be the topic of the work during week 12's lab, and the TAs should be used to ask for help.
The deadline is Saturday April 12th at 11:55pm. Although this is past the end of the term, which ends on April 9th, since this is meant as a way to revise the final we are exceptionally revising the deadline. Full commented solutions will be posted at midnight - so you may immediately learn. Thus no late submissions will be accepted.
The program MUST run (when opened in IDLE, and executed using F5, it must not cause an error from the get go), or the grade will be an automatic zero.
This assignment can be done in group, but submission should be individual. It is highly recommended you work at least in part alone on this assignment: it is short enough that this should not be a hindrance, and it is meant as a recap of many aspects of the course and to prepare you for the final; so if you don't do it entirely yourself, you will not get the benefit of this study tool.
The assignment consists of one Python source code on Coursys (eventually, if you attempt one of the advanced tasks, you might need to submit a second file - for instance if you write a second code file for the simulations; only in this case may you submit a second file).
The main Python source code file must begin with the lines:
######################################## ### MAZE SOLVER (CMPT 120 Assignment #2) ### Date: <date> ### Team (name and SFU ID): ### - <name of first person> (<sfu id of first person>) ### - ... ########################################
For instance:
######################################## ### MAZE SOLVER (CMPT 120 Assignment #2) ### Date: April 1st 2014 ### Team (name and SFU ID): ### - Jeremie Lumbroso (jlumbros) ### - Peggy Wen (peggyw) ### - Seymour Hoffman (seyhoff) ########################################
The main tasks will allow a team to get full marks for this assignment. The advanced tasks should only be undertaken by students with a quiz 1 score beyond 6.50; and it is mandatory for students with a quiz 1 score of 10.00 to complete at least one advanced task.
Questions should be asked on the help list: cmpt-120-help@sfu.ca.
Using what you have learned on lists, and files, you must code the following aspects:
Grading: the assignment will be graded on 10 points + 5 extra points:
Note that although this assignment is graded on 10 points as assignment 1 was, it will be weighted less than the latter. Indeed assignment 1 required a significant amount of additional work and will be worth more. (Probably 65% for assignment 1 and 35% for assignment 2 - but will be adjusted in favor of students.)
The file will be formatted in this way:
########### # # # ### # # # # # # # # # ### # # # # # # # # # ### ### # # #M # # ##### # # # # # ###########
The entrance is the white square in the first column of the second row; the exit is in the last column of the first to last row. The maze may or may not contain a M for the minotaur. For clarity, though these characters S and E will not in the file, the starting point is marked S in the following example and exit is marked E:
########### S # # # ### # # # # # # # # # ### # # # # # # # # # ### ### # # #M # # ##### # # # # # E ###########
This maze will be contained in file "maze.txt": you must open the file, read its lines, and create a variable maze that contains a list of list in the following format (be careful this is not the same as was asked in Lecture 27):
[[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1], [-1, 0, -1, 0, -1, -1, -1, 0, -1, 0, -1], [-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1], [-1, 0, -1, -1, -1, 0, -1, 0, -1, 0, -1], [-1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1], [-1, 0, -1, -1, -1, 0, -1, -1, -1, 0, -1], [-1, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1], [-1, 0, -1, -1, -1, -1, -1, 0, -1, 0, -1], [-1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
We will refer to individual squares/coordinates as cells of the maze.
Above, I have created a newline for each sublist because that is more readable, but Python will print out the above matrix in the following way:
[[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1], [-1, 0, -1, 0, -1, -1, -1, 0, -1, 0, -1], [-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1], [-1, 0, -1, -1, -1, 0, -1, 0, -1, 0, -1], [-1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1], [-1, 0, -1, -1, -1, 0, -1, -1, -1, 0, -1], [-1, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1], [-1, 0, -1, -1, -1, -1, -1, 0, -1, 0, -1], [-1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
You will use a simple version of the Flood Fill algorithm. In this algorithm, we throw a metaphorical bucket of paint at the starting point and we let the paint flow and see if it ever reaches the exit. (This is the same method that is used in drawing program, when you use the bucket of paint to fill a closed shape.)
Here is how you will apply this Flood Fill algorithm; say that you have a source_color (an integer) and a dest_color (an integer):
You will define a function flood_fill which will not return anything, but will modify the list maze:
def flood_fill(maze, start_row, start_column, source_color, dest_color): ...
For instance, using the variable maze given above (see below for what START_ROW and START_COLUMN are):
>>> flood_fill(maze, START_ROW, START_COLUMN, 0, 1) >>> print maze [[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1], [-1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1], [-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1], [-1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1], [-1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1], [-1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1], [-1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1], [-1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1], [-1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
(I have put every sub-list on a different line, in truth Python would print a mess without going to the line.)
To make sure you have implemented this algorithm correctly, you should try it out on the example I just gave, to see if you obtain the same matrix in the end.
Solving the maze will involve doing several flood fills.
To understand how to solve the minotaur question (which is difficult), you might need to look at the picture below with a drawing program such as MS Paint on Windows, or Paintbrush on Mac OS X. In these drawing programs, open the picture below, and try to use the "Paint Bucket" tool to color the exit, BUT only clicking near the entrance. Using a clever sequence of "Paint Bucket" fills, you should be able to color the exit in the same color as the entrance (both of them red).
For this assignment, you are forbidden to use hard-coded values. Hard-coded values are when you are told to use, for instance, the value -1 to represent a wall, and you use -1 everywhere in your code.
You can instead, at the very top of your Python code file, define a constant.
Constants are variables that you are never supposed to change, once they have been assigned for the first time. It is useful (and a pretty widespread convention) to use ALL CAPITAL LETTERS for the names of constants.
WALL = -1 MINOTAUR = 2 ...
And then whenever you would use -1 in reference to a wall, you instead use the constant WALL. For instance, if you had written, something like this:
if ch == "#": line_lst.append(-1)
you would instead write:
if ch == "#": line_lst.append(WALL)
Another good example, is that the start and end position should also be expressed as constants:
START_ROW = 1 START_COLUMN = 0 END_ROW =... ...
Or the color fills above should be coded using constants as well. For instance, when you do the first flood fill, you should use a constant, for instance WALKED_1...
Here are a few advantages of this approach:
Using constants instead of hard-coded values is one of several techniques that improve code legibility, which is probably one of the most important skills a computer programmer should have - and one that is sorely lacking from a lot of professional programmers (which greatly hinders their performance).
Below are some test mazes. All these mazes can be solved (and should return "ALIVE"). It is your responsibility to modify them, and add some blocking walls or a minotaur to test whether your program works correctly in the other situations.
The following code might be useful to draw a maze with the turtle module. It needs you to have correctly loaded the maze, and also to have correctly defined the constant WALL (see above for details about constants).
This visualization function should help you debug your program if it does not work (much like PythonTutor helps you find out what is wrong in previous programs).
Its limitation is that it does not: a) draw progress (when you are flooding the maze), and b) draw the minotaur. These are features you could add yourself. Consult the documentation for turtle.fillcolor to find out how you can change the color of the squares (for instance to do a red square for the minotaur, a gray square for cells you have walked on, etc.)
def square(side, filled=False): import turtle if filled: turtle.fill(True) for i in range(4): turtle.fd(side) turtle.rt(90) turtle.fill(False) def draw_maze_turtle(maze): import turtle side = 10 turtle.reset() turtle.speed("fastest") turtle.ht() for i in range(len(maze)): for j in range(len(maze[0])): square(side, maze[i][j] == WALL) turtle.pu() turtle.fd(side) turtle.pd() turtle.pu() turtle.rt(180) turtle.fd(len(maze[0])*side) turtle.lt(90) turtle.fd(side) turtle.lt(90) turtle.pd() turtle.done()