X-Git-Url: https://plomlompom.com/repos/feed.xml?a=blobdiff_plain;f=new%2Fplomrogue%2Fmapping.py;h=ee3e9401677e947d0c9fedd64234f9bb94d59ffd;hb=796f6c0c96e3ad88ced605609fff540b280fbf81;hp=e21def88a96dbecfda2b3196e5c7e62c68d2cb7c;hpb=599f48bd1d9270cf154e885cf276adb05727507a;p=plomrogue2-experiments diff --git a/new/plomrogue/mapping.py b/new/plomrogue/mapping.py index e21def8..ee3e940 100644 --- a/new/plomrogue/mapping.py +++ b/new/plomrogue/mapping.py @@ -1,33 +1,26 @@ from plomrogue.errors import ArgError +import collections -class MapBase: +class YX(collections.namedtuple('YX', ('y', 'x'))): - def __init__(self, size=(0, 0)): - self.size = size - self.terrain = '?'*self.size_i + def __add__(self, other): + return YX(self.y + other.y, self.x + other.x) - @property - def size_i(self): - return self.size[0] * self.size[1] + def __sub__(self, other): + return YX(self.y - other.y, self.x - other.x) + + def __str__(self): + return 'Y:%s,X:%s' % (self.y, self.x) - def set_line(self, y, line): - height_map = self.size[0] - width_map = self.size[1] - if y >= height_map: - raise ArgError('too large row number %s' % y) - width_line = len(line) - if width_line > width_map: - raise ArgError('too large map line width %s' % width_line) - self.terrain = self.terrain[:y * width_map] + line +\ - self.terrain[(y + 1) * width_map:] - def get_position_index(self, yx): - return yx[0] * self.size[1] + yx[1] +class Map: -class Map(MapBase): + def __init__(self, size=YX(0, 0)): + self.size = size + self.terrain = '?'*self.size_i def __getitem__(self, yx): return self.terrain[self.get_position_index(yx)] @@ -41,13 +34,31 @@ class Map(MapBase): def __iter__(self): """Iterate over YX position coordinates.""" - for y in range(self.size[0]): - for x in range(self.size[1]): - yield [y, x] + for y in range(self.size.y): + for x in range(self.size.x): + yield YX(y, x) + + @property + def size_i(self): + return self.size.y * self.size.x + + def set_line(self, y, line): + height_map = self.size.y + width_map = self.size.x + if y >= height_map: + raise ArgError('too large row number %s' % y) + width_line = len(line) + if width_line > width_map: + raise ArgError('too large map line width %s' % width_line) + self.terrain = self.terrain[:y * width_map] + line +\ + self.terrain[(y + 1) * width_map:] + + def get_position_index(self, yx): + return yx.y * self.size.x + yx.x def lines(self): - width = self.size[1] - for y in range(self.size[0]): + width = self.size.x + for y in range(self.size.y): yield (y, self.terrain[y * width:(y + 1) * width]) def get_fov_map(self, yx): @@ -62,17 +73,15 @@ class Map(MapBase): def get_neighbors(self, pos): neighbors = {} - pos = tuple(pos) if not hasattr(self, 'neighbors_to'): self.neighbors_to = {} if pos in self.neighbors_to: return self.neighbors_to[pos] for direction in self.get_directions(): neighbors[direction] = None - try: - neighbors[direction] = self.move(pos, direction) - except GameError: - pass + neighbor_pos = self.move(pos, direction) + if neighbor_pos: + neighbors[direction] = neighbor_pos self.neighbors_to[pos] = neighbors return neighbors @@ -86,9 +95,9 @@ class Map(MapBase): def move(self, start_pos, direction): mover = getattr(self, 'move_' + direction) new_pos = mover(start_pos) - if new_pos[0] < 0 or new_pos[1] < 0 or \ - new_pos[0] >= self.size[0] or new_pos[1] >= self.size[1]: - raise GameError('would move outside map bounds') + if new_pos.y < 0 or new_pos.x < 0 or \ + new_pos.y >= self.size.y or new_pos.x >= self.size.x: + return None return new_pos @@ -96,20 +105,20 @@ class Map(MapBase): class MapWithLeftRightMoves(Map): def move_LEFT(self, start_pos): - return [start_pos[0], start_pos[1] - 1] + return YX(start_pos.y, start_pos.x - 1) def move_RIGHT(self, start_pos): - return [start_pos[0], start_pos[1] + 1] + return YX(start_pos.y, start_pos.x + 1) class MapSquare(MapWithLeftRightMoves): def move_UP(self, start_pos): - return [start_pos[0] - 1, start_pos[1]] + return YX(start_pos.y - 1, start_pos.x) def move_DOWN(self, start_pos): - return [start_pos[0] + 1, start_pos[1]] + return YX(start_pos.y + 1, start_pos.x) @@ -120,28 +129,28 @@ class MapHex(MapWithLeftRightMoves): self.fov_map_type = FovMapHex def move_UPLEFT(self, start_pos): - if start_pos[0] % 2 == 1: - return [start_pos[0] - 1, start_pos[1] - 1] + if start_pos.y % 2 == 1: + return YX(start_pos.y - 1, start_pos.x - 1) else: - return [start_pos[0] - 1, start_pos[1]] + return YX(start_pos.y - 1, start_pos.x) def move_UPRIGHT(self, start_pos): - if start_pos[0] % 2 == 1: - return [start_pos[0] - 1, start_pos[1]] + if start_pos.y % 2 == 1: + return YX(start_pos.y - 1, start_pos.x) else: - return [start_pos[0] - 1, start_pos[1] + 1] + return YX(start_pos.y - 1, start_pos.x + 1) def move_DOWNLEFT(self, start_pos): - if start_pos[0] % 2 == 1: - return [start_pos[0] + 1, start_pos[1] - 1] + if start_pos.y % 2 == 1: + return YX(start_pos.y + 1, start_pos.x - 1) else: - return [start_pos[0] + 1, start_pos[1]] + return YX(start_pos.y + 1, start_pos.x) def move_DOWNRIGHT(self, start_pos): - if start_pos[0] % 2 == 1: - return [start_pos[0] + 1, start_pos[1]] + if start_pos.y % 2 == 1: + return YX(start_pos.y + 1, start_pos.x) else: - return [start_pos[0] + 1, start_pos[1] + 1] + return YX(start_pos.y + 1, start_pos.x + 1) @@ -150,6 +159,7 @@ class FovMap: def __init__(self, source_map, yx): self.source_map = source_map self.size = self.source_map.size + self.fov_radius = (self.size.y / 2) - 0.5 self.terrain = '?' * self.size_i self[yx] = '.' self.shadow_cones = [] @@ -225,11 +235,11 @@ class FovMap: def basic_circle_out_move(self, pos, direction): """Move position pos into direction. Return whether still in map.""" mover = getattr(self, 'move_' + direction) - pos[:] = mover(pos) - if pos[0] < 0 or pos[1] < 0 or \ - pos[0] >= self.size[0] or pos[1] >= self.size[1]: - return False - return True + pos = mover(pos) + if pos.y < 0 or pos.x < 0 or \ + pos.y >= self.size.y or pos.x >= self.size.x: + return pos, False + return pos, True def circle_out(self, yx, f): # Optimization potential: Precalculate movement positions. (How to check @@ -240,17 +250,21 @@ class FovMap: # would lose shade growth through hexes at shade borders.) # TODO: Start circling only in earliest obstacle distance. + # TODO: get rid of circle_in_map logic circle_in_map = True distance = 1 - yx = yx[:] + yx = YX(yx.y, yx.x) #print('DEBUG CIRCLE_OUT', yx) while circle_in_map: + if distance > self.fov_radius: + break circle_in_map = False - self.basic_circle_out_move(yx, 'RIGHT') + yx, _ = self.basic_circle_out_move(yx, 'RIGHT') for dir_i in range(len(self.circle_out_directions)): for dir_progress in range(distance): direction = self.circle_out_directions[dir_i] - if self.circle_out_move(yx, direction): + yx, test = self.circle_out_move(yx, direction) + if test: f(yx, distance, dir_i, dir_progress) circle_in_map = True distance += 1