1
2 from locals import WRAP_REPEAT, WRAP_CLAMP, WRAP_ERROR
3 from util import saturate
4
6
12
13 """Create a grid object.
14
15 node_factory -- Callable that takes the x and y coordinate of the node
16 and returns a node object. x_wrap and y_wrap parameters should be
17 one of (WRAP_REPEAT, WRAP_CLAMP, WRAP_ERROR).
18
19 width -- Width of the grid.
20 height -- Height of the grid.
21 x_wrap -- How to handle out of range x coordinates
22 y_wrap -- How to handle out of range y coordinates
23
24 """
25
26 self.node_factory = node_factory
27 self.width = width
28 self.height = height
29
30 self.nodes = [ [node_factory(x, y) for x in xrange(width)] \
31 for y in xrange(height)]
32
33 self._x_wrap = x_wrap
34 self._y_wrap = y_wrap
35
36 self._wrap_functions = [ self._make_wrap(self._x_wrap, self.width),
37 self._make_wrap(self._y_wrap, self.height) ]
38
39
45 x_wrap = property(_get_x_wrap, _set_x_wrap, None, "X wrap")
46
52 y_wrap = property(_get_y_wrap, _set_y_wrap, None, "Y wrap")
53
54
56
57 if wrap == WRAP_NONE:
58 def do_wrap(value):
59 return value
60
61 elif wrap == WRAP_REPEAT:
62 def do_wrap(value):
63 return value % edge
64
65 elif wrap == WRAP_CLAMP:
66 def do_wrap(value):
67 if value < 0:
68 return 0
69 if value >= edge:
70 value = edge
71 return value
72
73 elif wrap == WRAP_ERROR:
74 def do_wrap(value):
75 if value < 0 or value >= edge:
76 raise IndexError("coordinate out of range")
77
78 else:
79 raise ValueError("Unknown wrap mode")
80
81 return do_wrap
82
83
84 - def wrap(self, coord):
89
90
92 """Wraps an x coordinate.
93
94 x -- X Coordinate
95
96 """
97
98 return self._wrap_functions[0](x)
99
101 """Wraps a y coordinate.
102
103 y -- Y Coordinate.
104
105 """
106
107 return self._wrap_functions[1](y)
108
109
111
112 """Retrieves the size of the grid as a tuple (width, height)."""
113
114 return self.width, self.height
115
116
118
119 x, y = coord
120
121 if isinstance(x, slice) or isinstance(y, slice):
122 if isinstance(x, slice):
123 x_indices = x.indices(self.width)
124 else:
125 x_indices = [x]
126
127 if isinstance(y, slice):
128 y_indices = y.indices(self.height)
129 else:
130 y_indices = [y]
131
132 try:
133 wrap_x, wrap_y = self._wrap_functions
134
135 ret = []
136
137 for y_index in xrange(*y_indices):
138 nodes_y = self.nodes[ wrap_y(y_index) ]
139
140 for x_index in xrange(*x_indices):
141 ret.append( nodes_y[ wrap_x(x_index) ] )
142
143 except IndexError:
144 raise IndexError("Slice out of range")
145
146 return ret
147
148
149 x, y = self.wrap(coord)
150
151 if x < 0 or y < 0:
152 raise IndexError("coordinate out of range")
153
154 try:
155 return self.nodes[y][x]
156 except IndexError:
157 raise IndexError("coordinate out of range")
158
159
161
162 for row in self.nodes:
163 for node in row:
164 yield node
165
166
168
169 for row in self.nodes:
170 if node in row:
171 return True
172
173 return False
174
175
177
178 """Resets the grid."""
179
180 node_factory = self.node_factory
181
182 self.nodes[:] = [ [node_factory(x, y) for x in xrange(width)] \
183 for y in xrange(height)]
184
185
186 - def get(self, coord, default=None):
187
188 """Retrieves a node from the grid.
189
190 coord -- Coordinate to retrieve
191 default -- Default value to use if coord is out of range
192
193 """
194
195 x, y = self.wrap(coord)
196
197 if x < 0 or y < 0 or x >= self.width or y >= self.height:
198 if default is not None:
199 return default
200 else:
201 raise IndexError("coordinate out of range")
202
203 return self.nodes[y][x]
204
205
206 - def get_nodes(self, coord, size, wrap=False):
207
208 width = self.width
209 height = self.height
210
211 x1, y1 = coord
212 x1 = saturate(x1, 0, width)
213 y1 = saturate(y1, 0, height)
214 w, h = size
215 x2, y2 = (x+w, y+h)
216 x = saturate(x, 0, width)
217 y = saturate(y, 0, height)
218
219 if x1 > x2:
220 x1, x2 = x2, x1
221 if y1 > y2:
222 y1, y2 = y2, y1
223
224 wrap_x, wrap_y = self._wrap_functions
225
226 nodes = self.nodes
227 return [self.nodes[y_coord][x1:x2] for y_coord in xrange(y1, y2)]
228
229
230
231
232 if __name__ == "__main__":
233
238 return str(self.coord)
240 return str(self.coord)
241
242 g = Grid(Square, 100, 100, x_wrap = WRAP_REPEAT)
243
244 for square in g:
245 print str(square)
246
247 print g[10:20, 10:20]
248 print g.get_nodes((-2, 0), (5, 5))
249