-
Notifications
You must be signed in to change notification settings - Fork 1
/
triangle_grid.py
408 lines (339 loc) · 13.3 KB
/
triangle_grid.py
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
from color import RGB
def make_tri(model, n_rows):
return TriangleGrid(model, n_rows)
def calc_last_row_len(max_row):
row_len = 1
curr_row = 1
while curr_row < max_row:
if max_row == 1:
row_len = 1
else:
row_len += 2
curr_row += 1
return row_len
##
## Triangle Grid class to represent one strip
##
# Some reading on grids http://www-cs-students.stanford.edu/~amitp/game-programming/grids/
class TriangleGrid(object):
def __init__(self, model, n_rows):
self._model = model
self._n_rows = n_rows
self._len_of_last_row = calc_last_row_len(n_rows)
self._triangle_grid = [[None for i in range(self._len_of_last_row)] for j in range(self._n_rows)] #B/C this way of building a 2d array give you buggy garbage where setting [0][0] assigns all rows at posn [0] the value you are seetting[[None]*self.len_of_last_row]*self.n_rows
self._build_triangle_array_and_grid(n_rows)
def __str__(self):
return str("ME")
def __repr__(self):
print("what is this for?")
#OMG, this is such a nighmare... but it works...
def _build_triangle_array_and_grid(self, n_rows):
self._cells = []
if n_rows < 1:
raise Exception('row num must be 1+', n_rows)
if n_rows > 16:
raise Exception('row num must be <15')
if len(self._cells) > 0:
raise Exception('You have already built a triangle grid, clear this one first')
#By 'Y' I mean column..... sorry
grid_y_start_pos = (int(self._len_of_last_row)-1)//2
grid_y_curr_pos = grid_y_start_pos
row_len = 0
end_cell_id = 0
cell_id = 0
end_cell_id = 0
top_pixel = 73 #pointy top
btm_pixel = 67 #flat btm
curr_row = 0
while curr_row < n_rows:
# print "Curr Row:", curr_row
left_set = False
cells_added = 0
up_down = 'up'
l_corner = False
r_corner = False
top = False
if curr_row == n_rows:
l_corner = True
else:
l_corner = False
is_l_edge = False
is_r_edge = False
is_btm_edge = False
loop_start = True
row_pos = 1
while cell_id <= end_cell_id:
if curr_row == n_rows and cell_id == end_cell_id+1:
r_corner = True
else:
r_corner = False
if curr_row == 0:
top = True
else:
top = False
if loop_start is True:
is_l_edge = True
else:
is_l_edge = False
if cell_id == end_cell_id+1:
is_r_edge = True
else:
is_r_edge = False
if curr_row == n_rows:
if up_down in 'up':
is_btm_edge = True
else:
is_btm_edge = False
else:
is_btm_edge = False
cells_added += 1
tco = None #triagnel cell object
if up_down == 'up':
tco = TriangleCell(cell_id, curr_row, up_down, top, l_corner, r_corner, is_l_edge, is_r_edge, is_btm_edge, row_pos, [top_pixel, top_pixel-1, top_pixel-2, top_pixel-3, top_pixel-4, top_pixel-5])
self._cells.append(tco)
top_pixel -= 6
up_down = 'down'
else:
if curr_row >1:
tco = TriangleCell(cell_id, curr_row, up_down, top, l_corner, r_corner, is_l_edge, is_r_edge, is_btm_edge, row_pos, [btm_pixel, btm_pixel+1, btm_pixel+2, btm_pixel+3, btm_pixel+4, btm_pixel+5])
self._cells.append(tco)
btm_pixel += 6
else:
tco = TriangleCell(cell_id, curr_row, up_down, top, l_corner, r_corner, is_l_edge, is_r_edge, is_btm_edge, row_pos, [btm_pixel, btm_pixel-1, btm_pixel-2, btm_pixel-3, btm_pixel-4, btm_pixel-5])
self._cells.append(tco)
btm_pixel -= 6
up_down = 'up'
#Add Cell To Triangle Grid!
tco.add_row_col(curr_row, grid_y_curr_pos)
self._triangle_grid[curr_row][grid_y_curr_pos] = tco
grid_y_curr_pos += 1
if l_corner is True:
l_corner = False
loop_start = False
row_pos += 1
cell_id +=1
if cell_id == end_cell_id:
up_down = 'up'
end_cell_id += 2 + cells_added
grid_y_curr_pos = grid_y_start_pos - curr_row-1
curr_row += 1
btm_pixel -= 2 #(curr_row*6)+7
if curr_row > 1:
btm_pixel -= (curr_row*6)+9+9
top_pixel -= (curr_row*6)+9
def go(self):
self._model.go()
def clear(self):
self.set_all_cells(RGB( 0, 0, 0))
self.go()
def get_cells(self):
return self._cells
def get_triangle_grid(self):
return self._triangle_grid
def get_cell_by_grid_coords(self, rown, coln):
"RETURNS cell object or None if no cell is mapped to the coord"
if rown > self._n_rows:
return None
elif coln > self._len_of_last_row:
return None
else:
return self._triangle_grid[rown][coln]
def get_cell_by_id(self, cell_id):
return self._cells[cell_id+1]
def get_cell_by_array_posn(self, arr_pos):
return self._cells[arr_pos]
def set_cell(self, cell, color):
if cell is None:
print("WARNING: Skipping 'Nonetype' cell")
else:
for pixel in cell.get_pixels():
self._model.set_pixel(pixel, color, cell.get_id())
def set_cell_by_cellid(self, cell, color):
for pixel in self._cells[cell].get_pixels():
self._model.set_pixel(pixel, color, cell)
def get_all_cells(self):
"Return the list of valid cell IDs"
return self._cells
def set_cells_by_cellid(self, cells, color):
for cell in cells:
for pixel in self._cells[cell].get_pixels():
self._model.set_pixel(pixel, color, cell.get_id())
def set_cells(self, cells, color):
for cell in cells:
if cell is None:
print("WARNING: Skipping 'Nonetype' cell")
else:
for pixel in cell.get_pixels():
self._model.set_pixel(pixel, color, cell.get_id())
def set_all_cells(self, color):
for cell in self._cells:
for pixel in cell.get_pixels():
self._model.set_pixel(pixel, color, cell.get_id())
def set_pixel(self, pixel, color, cellid):
self._model.set_pixel(pixel, color, cellid) ###Have to pass the cellid through b/c the simulator does not understand pixels
def clear(self):
self.set_all_cells(RGB(0,0,0))
self.go()
def go(self):
self._model.go()
# convenience methods for grabbing useful parts of the triangle grid
def get_left_side_cells(self):
cells = []
for i in self._cells:
if i.is_left_edge():
cells.append(i)
return cells
def get_right_side_cells(self):
cells = []
for i in self._cells:
if i.is_right_edge():
cells.append(i)
return cells
def get_bottom_side_cells(self):
cells = []
for i in self._cells:
if i.is_bottom_edge():
cells.append(i)
return cells
def get_up_cells(self):
cells = []
for i in self._cells:
if i.is_up():
cells.append(i)
return cells
def get_down_cells(self):
cells = []
for i in self._cells:
if i.is_down():
cells.append(i)
return cells
def is_edge(self, cell):
if cell._l_edge:
return True
elif cell._r_edge:
return True
elif cell._btm_side:
return True
else:
return False
# Triangle Grid Helper Functions
def get_edge_neighbors_by_coord(self, row, col):
"returned in a tuple of (left neighbor, middle neighbor, right neighbor)"
"Where left is the edge directly to the left of the cell, regardless of up/down orientation"
"Where middle is either the top or bottom neighbor depending where the edge is. the cell knows its up/down orientation"
"Right neighbor is the cell immediately to the right."
cell = self.get_cell_by_grid_coords(row, col)
if cell is None:
return None
else:
l = None
m = None
r = None
if cell.is_up():
l = self.get_cell_by_grid_coords(row, col-1)
m = self.get_cell_by_grid_coords(row+1, col)
r = self.get_cell_by_grid_coords(row, col+1)
else:
l = self.get_cell_by_grid_coords(row, col-1)
m = self.get_cell_by_grid_coords(row-1, col)
r = self.get_cell_by_grid_coords(row, col+1)
return (l, m, r)
def get_edge_neighbors_by_cell(self, cell):
return self.get_edge_neighbors_by_coord(cell.get_row_num(), cell.get_col_pos())
def get_vertex_neighbors_by_coord(self, row, col):
"Return the neighbors whose vertexes are point to point"
"Uses same logic as edge_neighbors, left, middle, right"
cell = self.get_cell_by_grid_coords(row, col)
if cell is None:
return None
else:
l = None
m = None
r = None
if cell.is_up():
l = self.get_cell_by_grid_coords(row+1, col-1)
m = self.get_cell_by_grid_coords(row-1, col)
r = self.get_cell_by_grid_coords(row+1, col+1)
else:
l = self.get_cell_by_grid_coords(row-1, col-1)
m = self.get_cell_by_grid_coords(row+1, col)
r = self.get_cell_by_grid_coords(row-1, col+1)
return (l, m, r)
def get_vertex_neighbors_by_cell(self, cell):
return self.get_vertex_neighbors_by_coord(cell.get_row_num(), cell.get_col_pos())
def get_hexagon_from_btm_cell_by_coords(self, row, col):
"Given the coordinates of an up facing cell, return the surrounding cells which will make "
"A hexagon with the specified cell as the base"
"the tuple will begin with the upper left cell, then it's upper neighbor, then its upper right"
"neighbor.... and so on"
cell = self.get_cell_by_grid_coords(row, col)
if cell is None:
return None
else:
a = self.get_cell_by_grid_coords(row, col-1)
b =self.get_cell_by_grid_coords(row-1, col-1)
c =self.get_cell_by_grid_coords(row-1, col)
d =self.get_cell_by_grid_coords(row-1, col+1)
e =self.get_cell_by_grid_coords(row, col+1)
return (cell, a, b, c, d, e)
def get_hexagon_from_btm_cell_by_cell(self, cell):
return self.get_hexagon_from_btm_cell_by_coords(cell.get_row_num(), cell.get_col_pos())
class TriangleCell(object):
def __init__(self, cell_id, row, up_down, is_top, l_corner, r_corner, is_l_edge, is_r_edge, is_btm_edge, row_pos, pixels=[]):
self._id = cell_id
self._row_n = row
self._row_pos = row_pos
self._l_edge = is_l_edge
if cell_id in [1, 3]:
self._l_edge = True
self._r_edge = is_r_edge
if cell_id in [1, 3]:
self._r_edge= True
self._top_cell = is_top
self._btm_right = r_corner
self._btm_left = l_corner
self._pointy_side = up_down
self._btm_side = is_btm_edge
self._up_down = up_down
self._pixels = pixels #do we really need a pixel class?
def add_row_col(self, r, c):
self._grid_row_n = r
self._grid_col_n = c
def get_id(self):
return self._id
def get_pixels(self,oriented=True):
if oriented:
if self._up_down is 'up':
return self._pixels
else:
if self._row_n == 2: ####FIXME Something wrrong with bottom cells in row 2 and maybe deeper
return self._pixels
else:
return self._pixels[::-1]
else:
return self._pixels
def get_row_num(self):
return self._grid_row_n
def get_col_pos(self):
return self._grid_col_n
def is_left_edge(self):
return self._l_edge
def is_right_edge(self):
return self._r_edge
def is_bottom_edge(self):
return self._btm_side
def is_top(self):
return self._top_cell
def is_right_btm_corner(self):
return self._btm_right
def is_left_btm_corner(self):
return self._btm_left
def row_num(self):
return self._row_n
def is_up(self):
return self._up_down in "up"
def is_down(self):
return self._up_down in "down"
class TriangleCellPixel(object):
def __init__(self):
pass