Congratulations on the initiative!
So here we go:
The "easy to start and hard to continue" way of doing this kind of thing is to use sequences within sequences.
Anyway, you’re defining your maze as a multiline string - so you’d better turn it into a list-in-lists data structure so you can address each point automatically. To do this, we can take the following steps:
break the string with the whole maze where there is a line break (character n). Use each obtained substring as "as is" since a string is a string. (A \n
the more you put right into the inpicio of the maze avoids an empty line at the beginning of the same and it is important):
maze = maze.split("\n")
Ready. Now maze[1][5]
will access the sixth character in the second line. The "split" method breaks a string into a list of strings in the specified separator (and omits the separator), and is sufficient for this. Both lists and strings are sequences - so maze[n]
will retrieve you a line from the maze.
Now, mazes of this kind are pretty cool things to start understanding Python Object Orientation. Just implement the method __getitem__
in a class, and Python can retrieve elements from there with the syntax [ ]
, as if it were a native sequence - and, if our __getitem__
support indices separated by ,
, that are passed as tuples, we can access elements in the maze as maze[x, y]
with only a few lines of code.
To allow the maze to be changeable, this is: you can insert new elements into it after created, I will use lists inside lists instead of strings inside lists:
class Maze:
def __init__(self, text_maze):
self.maze = [[char for char in line] for line in text_maze.split() if line.strip()]
def __getitem__(self, index):
# getitem simples, vai retornar um erro do próprio Python
# se for acessado um elemento com índice errado
x, y = index
return self.maze[y][x]
def __setitem__(self, index, value):
x, y = index
self.maze[y][x] = value
def __len__(self):
return len(self.maze)
def __repr__(self):
return "\n".join("".join(char for char in line) for line in self.maze)
Now, you will continue there, will give more tarbalho you plot elements within the maze (like a character walking, or even the algorithm showing the paths already traveled) in text mode, to which use a
True graphic mode and see the maze as colored blobs on the screen.
The terminal is full of pranks - while graphic functions are made for this.
Look at - taking advantage of what I had made of OOP, I inherited the class labyrinth, and put the extra code for the labrinto draw using the Tkinter.
See what you can do with another 40 lines (well spaced) and using the Tkinter - (the reference for the Tkinter canvas is here: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/canvas-methods.html )
maze_data = """\
###########################
# # ## ##
# ##### ### # # ######## ##
# # ### # # #
# ### # ##### # # ### ### #
# # # # # #
### #### #### ######### # #
### # ## ## # # #
# ### ## ## #### ## # #
# ### ## #### ## # ## ### #
# # ## ## # ## # #
### ### ######## # ## ## ##
# ## X#
###########################
"""
import tkinter
class Maze:
def __init__(self, text_maze):
self.maze = [[char for char in line] for line in text_maze.split("\n") if line.strip()]
print(self)
def __getitem__(self, index):
# getitem simples, vai retornar um erro do próprio Python
# se for acessado um elemento com índice errado
x, y = index
return self.maze[y][x]
def __setitem__(self, index, value):
x, y = index
self.maze[y][x] = value
def __len__(self):
return len(self.maze)
def __repr__(self):
return "\n".join("".join(char for char in line) for line in self.maze)
width = property(lambda self: len(self.maze[0]))
height = property(lambda self: len(self.maze))
BLOCK_SIZE = 24
COLORS = {"#": "#000", " ": "#fff", "X":"#f00"}
class TkinterMaze(Maze):
def __init__(self, root, text_maze):
super().__init__(text_maze)
self.root = root
self.canvas = tkinter.Canvas(root, width=self.width * BLOCK_SIZE, height=self.height * BLOCK_SIZE)
self.canvas.pack()
self.rectangles = {}
self.update()
def clear(self):
for coordinates, rect_id in self.rectangles.items():
self.canvas.delete(rect_id)
def update(self):
self.clear()
for (x, y), char in self:
color = COLORS[char]
rect_id = self.canvas.create_rectangle(
x * BLOCK_SIZE,
y * BLOCK_SIZE,
(x + 1) * BLOCK_SIZE,
(y + 1) * BLOCK_SIZE,
fill = color,
width = 0
)
self.rectangles[x, y] = rect_id
def __iter__(self):
for y, line in enumerate(self.maze):
for x, char in enumerate(line):
yield ((x,y), char)
def main():
window = tkinter.Tk()
maze = TkinterMaze(window, maze_data)
window.bind("destroy", window.destroy)
tkinter.mainloop()
main()
Looking at the Tkinter documentation a little bit, you can use the "bind" of events to receive keystrokes and make the character walk through the maze. (A better implementation will be with persongaem in a separate class, with a reference to the labyrinth - ai using the "getitem" it can know where it can go where it can’t go. He can share the ". canvas" of the maze to draw on the same screen, or the labrinto can incorporate another "layer" to draw objects that are not wall)
I think you mean that:
maze[1][2]
to know the content of the sublist, and place the entire code when you can!– nelson450
Ss, but how do I do this with the index? because I need to know the position of the (END) on the map, I use the list for the y-axis and the sub-list for x, but I don’t know how to locate the variable. I think about making a loop while, but I’m out of ideas.
– Marcos Vinícius
I think this is it: Maze.find(END)
– nelson450
Would there be another way to return the position in numbers? type the position of the END[13][26] (sub-list 13, at heading 26)??
– Marcos Vinícius