This code has serious problems. Let me start the design from scratch. This, I hope, will serve as a good lesson in the design and creation of classes and data structures.
To get started, you need to organize your code around the Map
class, which then presents your rooms as a grid. You should not think of “room 1,” “room 2,” etc. (Which is very difficult to track on a map) and, rather, think about rooms in terms of coordinates.
Now there are several possible functions that we ignore at the beginning, including the player who sees only the rooms he was in, the player who remains in the center of the map, and the diagonal paths. If you want them, you can put them later as soon as the core functionality works. So far, we are aiming for something that looks something like this:
[ ]-[u] [ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ]
That is, we present it as a grid, where some rooms are connected, while others are not. Let each room have a coordinate pair, something like this:
0 1 2 3 0 [ ]-[u] [ ] [ ] | 1 [ ]-[ ]-[ ] [ ] | 2 [ ]-[ ]-[ ] [ ] | 3 [ ]-[ ]-[ ]-[ ]
Let x be along the vertex, and let y be along the side. The top left is (0, 0), the one that has [u]
in it (0, 1).
Now, what are the components of our Map
class?
map height: integer
card width: integer)
player_x, player_y: player coordinates
possible paths: a list of pairs of rooms that we can move between them. The above card will be presented as:
[((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1), (2, 1)), ((1, 0), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)), ((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3), (3, 3))]
Note that I ordered each pair in such a way that the first tuple goes first (which is important later).
So, now that we have our design, write that Map
class!
I can imagine the four methods we want: print_map
, move
and initializer. The initialization is simple: just set the four attributes listed above:
class Map: def __init__(self, height, width, player_x, player_y, paths): self.height = height self.width = width self.x = player_x self.y = player_y self.paths = paths
Now move
is simple enough. Given the direction n / e / s / w:
def move(self, direction): if direction == "n": if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths: print "Cannot go north" else: self.y -= 1
The move
function for the "north" simply checks if there is a path to the room above the one we are in.
Now for the most interesting part: map printing. You do this by self.height
through the rows (from 0 to self.height
) and column by column (from 0 to self.width
). (Note: you cannot use print
in this situation, since it automatically places a new line or a space after the line. Instead, we use sys.stdout.write .
def print_map(self): for y in range(0, self.height): # print the yth row of rooms for x in range(0, self.width): if self.x == x and self.y == y: sys.stdout.write("[u]") # this is the player room else: sys.stdout.write("[ ]") # empty room # now see whether there a path to the next room if ((x, y), (x + 1, y)) in self.paths: sys.stdout.write("-") else: sys.stdout.write(" ") # now that we've written the rooms, draw paths to next row print # newline for x in range(0, self.width): sys.stdout.write(" ") # spaces for above room if ((x, y), (x, y + 1)) in self.paths: sys.stdout.write("| ") else: sys.stdout.write(" ") print
Now, let everyone try it together. Here is the code:
import sys class Map: def __init__(self, height, width, player_x, player_y, paths): self.height = height self.width = width self.x = player_x self.y = player_y self.paths = paths def move(self, direction): if direction == "n": if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths: print "Cannot go north" else: self.y -= 1 if direction == "s": if ((self.x, self.y), (self.x, self.y + 1)) not in self.paths: print "Cannot go south" else: self.y += 1 if direction == "e": if ((self.x, self.y), (self.x + 1, self.y)) not in self.paths: print "Cannot go east" else: self.x += 1 if direction == "w": if ((self.x - 1, self.y), (self.x, self.y)) not in self.paths: print "Cannot go west" else: self.x -= 1 def print_map(self): for y in range(0, self.height): # print the yth row of rooms for x in range(0, self.width): if self.x == x and self.y == y: sys.stdout.write("[u]") # this is the player room else: sys.stdout.write("[ ]") # empty room # now see whether there a path to the next room if ((x, y), (x + 1, y)) in self.paths: sys.stdout.write("-") else: sys.stdout.write(" ") # now that we've written the rooms, draw paths to next row print # newline for x in range(0, self.width): sys.stdout.write(" ") # spaces for above room if ((x, y), (x, y + 1)) in self.paths: sys.stdout.write("| ") else: sys.stdout.write(" ") print paths = [((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1), (2, 1)), ((1, 1), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)), ((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3), (3, 3))] m = Map(4, 4, 0, 0, paths) while True: m.print_map() direction = raw_input("What direction do you want to move? [n/e/s/w] ") m.move(direction)
Please note that I have added a section below, which creates a map and allows the player to move around it. Here's what it looks like when it starts:
Davids-MacBook-Air:test dgrtwo$ python Map.py [u]-[ ] [ ] [ ] | [ ] [ ]-[ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ] What direction do you want to move? [n/e/s/w] e [ ]-[u] [ ] [ ] | [ ] [ ]-[ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ] What direction do you want to move? [n/e/s/w] s [ ]-[ ] [ ] [ ] | [ ] [u]-[ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ] What direction do you want to move? [n/e/s/w] w Cannot go west [ ]-[ ] [ ] [ ] | [ ] [u]-[ ] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ] What direction do you want to move? [n/e/s/w] e [ ]-[ ] [ ] [ ] | [ ] [ ]-[u] [ ] | [ ]-[ ]-[ ] [ ] | [ ]-[ ]-[ ]-[ ]
There are many improvements that can be made to this code (in particular, the move
method is repeated), but this is a good start. Try making a 20x20 card and you will see that it is just expanding.
ETA: I have to point out that print_map
can be rewritten in a much shorter form, something like:
def print_map(self): for y in range(0, self.height): print "".join(["[%s]%s" % ("u" if self.x == x and self.y == y else " ", "-" if ((x, y), (x + 1, y)) in self.paths else " ") for x in range(0, self.width)]) print " " + " ".join(["|" if ((x, y), (x, y + 1)) in self.paths else " " for x in range(0, self.width)])
But this is a bit more intense.