-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap.py
More file actions
133 lines (111 loc) · 4.19 KB
/
Copy pathmap.py
File metadata and controls
133 lines (111 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from argparse import ArgumentParser
import os
import numpy as np
from drawing import Container
from cell import CELL
class MapEditor(Container):
def __init__(self, width, height, rows, cols, map_file):
"""
User interface to create or edit a map. The map is saved to a file when
the window is closed. By clicking on a cell, the cell type is cycled
through the following values:
- 0: Empty
- 1: Target
- 2: Wall
- 3: Start
Parameters
----------
width : int
Width of the window.
height : int
Height of the window.
rows : int
Number of rows of the grid.
cols : int
Number of columns of the grid.
map_file : str
File to save the map. If the file exists, the initial state is
loaded from it.
"""
self.window_dim = np.array([width, height])
self.map_dim = np.array([cols, rows], dtype=int)
self.map_file = map_file
super().__init__(self.window_dim[0], self.window_dim[1], frame_rate=20)
def setup(self):
"""
Setup the grid and the event binding.
"""
if os.path.exists(self.map_file):
self.grid = np.loadtxt(self.map_file, dtype=int).T
else:
self.grid = np.zeros(self.map_dim, dtype=int)
self.grid = np.vectorize(CELL)(self.grid)
self.cell_size = self.window_dim / self.grid.shape
self.bind("<Button-1>", self.cycle_cell)
def draw(self):
"""
Draw the grid on the canvas. The color of the cells is determined by the
cell type.
"""
for i in range(self.grid.shape[0]):
for j in range(self.grid.shape[1]):
self.canvas.create_rectangle(i * self.cell_size[0], j * self.cell_size[1],
(i + 1) * self.cell_size[0], (j + 1) * self.cell_size[1],
fill=self.grid[i][j].get_color(), outline="")
self.draw_grid(self.grid.shape[0], self.grid.shape[1], self.cell_size, color="black", linewidth=1.5)
def shutdown(self):
"""
Save the map to a file when the window is closed.
"""
MapLoader.save_map(self.grid, self.map_file)
def cycle_cell(self, event):
"""
Cycle the cell type when a cell is clicked.
Parameters
----------
event : tkinter.Event
The event object.
"""
coords = np.array([event.x, event.y])
i, j = np.clip(coords // self.cell_size, 0, np.array(self.grid.shape) - 1).astype(int)
self.grid[i][j] = CELL((self.grid[i][j].value + 1) % 4)
class MapLoader:
@staticmethod
def load_map(map_file):
"""
Load a map from a file.
Parameters
----------
map_file : str
The file to load the map from.
Returns
-------
np.ndarray
The map.
"""
if os.path.exists(map_file):
map = np.loadtxt(map_file, dtype=int).T
return np.vectorize(CELL)(map)
else:
raise FileNotFoundError(f"Map file {map_file} not found.")
@staticmethod
def save_map(map, map_file):
"""
Save a map to a file.
Parameters
----------
map : np.ndarray of CELL
The map to save.
map_file : str
The file to save the map to.
"""
np.savetxt(map_file, np.vectorize(lambda x: x.value)(map).T, fmt="%d")
if __name__ == "__main__":
parser = ArgumentParser(description="Map Editor")
parser.add_argument("--width", type=int, default=500, help="Width of the window")
parser.add_argument("--height", type=int, default=500, help="Height of the window")
parser.add_argument("--cols", type=int, default=10, help="Number of columns")
parser.add_argument("--rows", type=int, default=10, help="Number of rows")
parser.add_argument("--map_file", type=str, default=os.path.join(os.getcwd(), "maps/map.txt"), help="File to save the map (or load if it exists)")
args = parser.parse_args()
MapEditor(args.width, args.height, args.rows, args.cols, args.map_file)