home · contact · privacy
Use smarter YX class for y,x coordinates/sizes.
authorChristian Heller <c.heller@plomlompom.de>
Sat, 27 Apr 2019 19:04:10 +0000 (21:04 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 27 Apr 2019 19:04:10 +0000 (21:04 +0200)
new/example_client.py
new/plomrogue/commands.py
new/plomrogue/game.py
new/plomrogue/mapping.py
new/plomrogue/misc.py
new/plomrogue/parser.py
new/plomrogue/tasks.py
new/plomrogue/things.py

index 8f7af6643f2d63425e79767f50a65dc706f579d3..230b045ac916deead9c79a21e5780664b7c51454 100755 (executable)
@@ -5,7 +5,7 @@ import threading
 from plomrogue.parser import ArgError, Parser
 from plomrogue.commands import cmd_PLAYER_ID, cmd_THING_HEALTH
 from plomrogue.game import Game, WorldBase
-from plomrogue.mapping import MapHex
+from plomrogue.mapping import MapHex, YX
 from plomrogue.io import PlomSocket
 from plomrogue.things import ThingBase
 import types
@@ -45,7 +45,7 @@ class ClientMap(MapHex):
                 else:
                     map_view_chars += [cell[0], cell[1]]
                 x += 1
-                if x == self.size[1]:
+                if x == self.size.x:
                     map_view_chars += ['\n']
                     x = 0
                     y += 1
@@ -62,9 +62,9 @@ class ClientMap(MapHex):
         else:
             for i in range(len(map_lines)):
                 map_lines[i] = '0' + map_lines[i]
-        self.y_cut(map_lines, center[0], size[0])
-        map_width = self.size[1] * 2 + 1
-        self.x_cut(map_lines, center[1] * 2, size[1], map_width)
+        self.y_cut(map_lines, center.y, size.y)
+        map_width = self.size.x * 2 + 1
+        self.x_cut(map_lines, center.x * 2, size.x, map_width)
         return map_lines
 
 
@@ -78,7 +78,7 @@ class World(WorldBase):
         """
         super().__init__(*args, **kwargs)
         self.map_ = ClientMap()
-        self.offset = (0,0)
+        self.offset = YX(0,0)
         self.player_inventory = []
         self.player_id = 0
         self.pickable_items = []
@@ -233,7 +233,7 @@ class Widget:
         self.check_updates = check_updates
         self.tui = tui
         self.start = start
-        self.win = curses.newwin(1, 1, self.start[0], self.start[1])
+        self.win = curses.newwin(1, 1, self.start.y, self.start.x)
         self.size_def = size  # store for re-calling .size on SIGWINCH
         self.size = size
         self.do_update = True
@@ -242,20 +242,22 @@ class Widget:
 
     @property
     def size(self):
-        return self.win.getmaxyx()
+        return YX(*self.win.getmaxyx())
 
     @size.setter
     def size(self, size):
         """Set window size. Size be y,x tuple. If y or x None, use legal max."""
         n_lines, n_cols = size
+        getmaxyx = YX(*self.tui.stdscr.getmaxyx())
         if n_lines is None:
-            n_lines = self.tui.stdscr.getmaxyx()[0] - self.start[0]
+            n_lines = getmaxyx.y - self.start.y
         if n_cols is None:
-            n_cols = self.tui.stdscr.getmaxyx()[1] - self.start[1]
+            n_cols = getmaxyx.x - self.start.x
         self.win.resize(n_lines, n_cols)
 
     def __len__(self):
-        return self.win.getmaxyx()[0] * self.win.getmaxyx()[1]
+        getmaxyx = YX(*self.win.getmaxyx())
+        return getmaxyx.y * getmaxyx.x
 
     def safe_write(self, foo):
 
@@ -280,9 +282,9 @@ class Widget:
         else:  # workaround to <https://stackoverflow.com/q/7063128>
             cut = chars_with_attrs[:len(self) - 1]
             last_char_with_attr = chars_with_attrs[len(self) - 1]
-            self.win.addstr(self.size[0] - 1, self.size[1] - 2,
+            self.win.addstr(self.size.y - 1, self.size.x - 2,
                             last_char_with_attr[0], last_char_with_attr[1])
-            self.win.insstr(self.size[0] - 1, self.size[1] - 2, ' ')
+            self.win.insstr(self.size.y - 1, self.size.x - 2, ' ')
             self.win.move(0, 0)
             for char_with_attr in cut:
                 self.win.addstr(char_with_attr[0], char_with_attr[1])
@@ -315,7 +317,7 @@ class TextLinesWidget(Widget):
 
     def draw(self):
         lines = self.get_text_lines()
-        line_width = self.size[1]
+        line_width = self.size.x
         to_join = []
         for line in lines:
             to_pad = line_width - (len(line) % line_width)
@@ -353,10 +355,11 @@ class PopUpWidget(Widget):
         size = (1, len(self.tui.popup_text))
         self.size = size
         self.size_def = size
-        offset_y = int((self.tui.stdscr.getmaxyx()[0] / 2) - (size[0] / 2))
-        offset_x = int((self.tui.stdscr.getmaxyx()[1] / 2) - (size[1] / 2))
-        self.start = (offset_y, offset_x)
-        self.win.mvwin(self.start[0], self.start[1])
+        getmaxyx = YX(*self.tui.stdscr.getmaxyx())
+        offset_y = int(getmaxyx.y / 2 - size.y / 2)
+        offset_x = int(getmaxyx.x / 2 - size.x / 2)
+        self.start = YX(offset_y, offset_x)
+        self.win.mvwin(self.start.y, self.start.x)
 
 
 class ItemsSelectorWidget(Widget):
@@ -385,7 +388,7 @@ class ItemsSelectorWidget(Widget):
             t = self.tui.game.world.get_thing(id_)
             lines += ['%s %s' % (pointer, t.type_)]
             counter += 1
-        line_width = self.size[1]
+        line_width = self.size.x
         to_join = []
         for line in lines:
             to_pad = line_width - (len(line) % line_width)
@@ -421,7 +424,7 @@ class MapWidget(Widget):
             return terrain_as_list
 
         def pad_or_cut_x(lines):
-            line_width = self.size[1]
+            line_width = self.size.x
             for y in range(len(lines)):
                 line = lines[y]
                 if line_width > len(line):
@@ -431,9 +434,9 @@ class MapWidget(Widget):
                     lines[y] = line[:line_width]
 
         def pad_y(lines):
-            if len(lines) < self.size[0]:
-                to_pad = self.size[0] - len(lines)
-                lines += to_pad * ['0' * self.size[1]]
+            if len(lines) < self.size.y:
+                to_pad = self.size.y - len(lines)
+                lines += to_pad * ['0' * self.size.x]
 
         def lines_to_colored_chars(lines):
             chars_with_attrs = []
@@ -503,7 +506,7 @@ class TUI:
         self.parser = Parser(self.game)
         self.to_update = {}
         self.item_pointer = 0
-        self.examiner_position = ((0,0), (0, 0))
+        self.examiner_position = (YX(0,0), YX(0, 0))
         self.examiner_mode = False
         self.popup_text = 'Hi bob'
         self.to_send = []
@@ -654,32 +657,31 @@ class TUI:
         init_colors()
 
         # With screen initialized, set up widgets with their curses windows.
-        edit_widget = TextLineWidget('SEND:', self, (0, 0), (1, 20))
-        edit_line_widget = EditWidget(self, (0, 6), (1, 14), ['edit'])
+        edit_widget = TextLineWidget('SEND:', self, YX(0, 0), YX(1, 20))
+        edit_line_widget = EditWidget(self, YX(0, 6), YX(1, 14), ['edit'])
         edit_widget.children += [edit_line_widget]
-        turn_widget = TextLineWidget('TURN:', self, (2, 0), (1, 20))
-        turn_widget.children += [TurnWidget(self, (2, 6), (1, 14), ['turn'])]
-        health_widget = TextLineWidget('HEALTH:', self, (3, 0), (1, 20))
-        health_widget.children += [HealthWidget(self, (3, 8), (1, 12), ['turn'])]
-        log_widget = LogWidget(self, (5, 0), (None, 20), ['log'])
-        descriptor_widget = DescriptorWidget(self, (5, 0), (None, 20),
+        turn_widget = TextLineWidget('TURN:', self, YX(2, 0), YX(1, 20))
+        turn_widget.children += [TurnWidget(self, YX(2, 6), YX(1, 14), ['turn'])]
+        health_widget = TextLineWidget('HEALTH:', self, YX(3, 0), YX(1, 20))
+        health_widget.children += [HealthWidget(self, YX(3, 8), YX(1, 12), ['turn'])]
+        log_widget = LogWidget(self, YX(5, 0), YX(None, 20), ['log'])
+        descriptor_widget = DescriptorWidget(self, YX(5, 0), YX(None, 20),
                                              ['map'], False)
-        map_widget = MapWidget(self, (0, 21), (None, None), ['map'])
+        map_widget = MapWidget(self, YX(0, 21), YX(None, None), ['map'])
         inventory_widget = ItemsSelectorWidget('INVENTORY:',
                                                self.game.world.player_inventory,
-                                               self, (0, 21), (None,
-                                                               None), ['inventory'],
-                                               False)
+                                               self, YX(0, 21), YX(None, None),
+                                               ['inventory'], False)
         pickable_items_widget = ItemsSelectorWidget('PICKABLE:',
                                                     self.game.world.pickable_items,
-                                                    self, (0, 21),
-                                                    (None, None),
+                                                    self, YX(0, 21),
+                                                    YX(None, None),
                                                     ['pickable_items'],
                                                     False)
         top_widgets = [edit_widget, turn_widget, health_widget, log_widget,
                        descriptor_widget, map_widget, inventory_widget,
                        pickable_items_widget]
-        popup_widget = PopUpWidget(self, (0, 0), (1, 1), visible=False)
+        popup_widget = PopUpWidget(self, YX(0, 0), YX(1, 1), visible=False)
 
         # Ensure initial window state before loop starts.
         for w in top_widgets:
index 48457f9ab1e4b82f49a32742a6693191c2ea8d83..c845ed1ce1dcc2135aad94b4696b768cb8ff86f4 100644 (file)
@@ -1,4 +1,4 @@
-from plomrogue.misc import quote, stringify_yx
+from plomrogue.misc import quote
 
 
 
@@ -104,18 +104,16 @@ def cmd_SAVE(game):
     with open(save_file_name, 'w') as f:
         write(f, 'TURN %s' % game.world.turn)
         write(f, 'SEED %s' % game.world.rand.prngod_seed)
-        write(f, 'MAP_SIZE ' + stringify_yx(game.world.map_size))
+        write(f, 'MAP_SIZE %s' % (game.world.map_size,))
         for map_pos in game.world.maps:
-            write(f, 'MAP ' + stringify_yx(map_pos))
+            write(f, 'MAP %s' % (map_pos,))
         for map_pos in game.world.maps:
             for y, line in game.world.maps[map_pos].lines():
-                 write(f, 'TERRAIN_LINE %s %5s %s' % (stringify_yx(map_pos),
-                                                      y, quote(line)))
+                 write(f, 'TERRAIN_LINE %s %5s %s' % (map_pos, y, quote(line)))
         for thing in game.world.things:
             write(f, 'THING_TYPE %s %s' % (thing.id_, thing.type_))
-            write(f, 'THING_POS %s %s %s' % (thing.id_,
-                                             stringify_yx(thing.position[0]),
-                                             stringify_yx(thing.position[1])))
+            write(f, 'THING_POS %s %s %s' % (thing.id_, thing.position[0],
+                                             thing.position[1]))
             if hasattr(thing, 'health'):
                 write(f, 'THING_HEALTH %s %s' % (thing.id_, thing.health))
             if len(thing.inventory) > 0:
index cd8f314be8d6fe12c0dff2a0ceeb08460bf2fdef..de6f0c03d00f22a23f278b5c8dfa4c08b8c05e52 100755 (executable)
@@ -8,10 +8,10 @@ from plomrogue.commands import (cmd_GEN_WORLD, cmd_GET_GAMESTATE,
                                 cmd_GET_PICKABLE_ITEMS, cmd_MAP_SIZE,
                                 cmd_TERRAIN_LINE, cmd_PLAYER_ID,
                                 cmd_TURN, cmd_SWITCH_PLAYER, cmd_SAVE)
-from plomrogue.mapping import MapHex
+from plomrogue.mapping import MapHex, YX
 from plomrogue.parser import Parser
 from plomrogue.io import GameIO
-from plomrogue.misc import quote, stringify_yx
+from plomrogue.misc import quote
 from plomrogue.things import Thing, ThingMonster, ThingHuman, ThingFood
 import random
 
@@ -67,7 +67,7 @@ class World(WorldBase):
         self.player_id = 0
         self.player_is_alive = True
         self.maps = {}
-        self.map_size = (1,1)
+        self.map_size = YX(1,1)
         self.rand = PRNGod(0)
 
     @property
@@ -101,11 +101,11 @@ class World(WorldBase):
             for thing in self.things[player_i+1:]:
                 thing.proceed()
             self.turn += 1
-            for pos in self.maps[(0,0)]:
-                if self.maps[(0,0)][pos] == '.' and \
-                   len(self.things_at_pos(((0,0), pos))) == 0 and \
+            for pos in self.maps[YX(0,0)]:
+                if self.maps[YX(0,0)][pos] == '.' and \
+                   len(self.things_at_pos((YX(0,0), pos))) == 0 and \
                    self.rand.random() > 0.999:
-                    self.add_thing_at('food', ((0,0), pos))
+                    self.add_thing_at('food', (YX(0,0), pos))
             for thing in self.things[:player_i]:
                 thing.proceed()
             self.player.proceed(is_AI=False)
@@ -122,9 +122,9 @@ class World(WorldBase):
 
         def add_thing_at_random(type_):
             while True:
-                new_pos = ((0,0),
-                           (self.rand.randint(0, yx[0] -1),
-                            self.rand.randint(0, yx[1] -1)))
+                new_pos = (YX(0,0),
+                           YX(self.rand.randint(0, yx.y - 1),
+                              self.rand.randint(0, yx.x - 1)))
                 if self.maps[new_pos[0]][new_pos[1]] != '.':
                     continue
                 if len(self.things_at_pos(new_pos)) > 0:
@@ -136,18 +136,18 @@ class World(WorldBase):
         self.turn = 0
         self.maps = {}
         self.map_size = yx
-        self.new_map((0,0))
-        self.new_map((0,1))
-        self.new_map((1,1))
-        self.new_map((1,0))
-        self.new_map((1,-1))
-        self.new_map((0,-1))
-        self.new_map((-1,-1))
-        self.new_map((-1,0))
-        self.new_map((-1,1))
+        self.new_map(YX(0,0))
+        self.new_map(YX(0,1))
+        self.new_map(YX(1,1))
+        self.new_map(YX(1,0))
+        self.new_map(YX(1,-1))
+        self.new_map(YX(0,-1))
+        self.new_map(YX(-1,-1))
+        self.new_map(YX(-1,0))
+        self.new_map(YX(-1,1))
         for map_pos in self.maps:
             map_ = self.maps[map_pos]
-            if (0,0) == map_pos:
+            if YX(0,0) == map_pos:
                 for pos in map_:
                     map_[pos] = self.rand.choice(('.', '.', '.', '.', 'x'))
             else:
@@ -199,7 +199,7 @@ class Game:
 
     def get_string_options(self, string_option_type):
         if string_option_type == 'direction':
-            return self.world.maps[(0,0)].get_directions()
+            return self.world.maps[YX(0,0)].get_directions()
         elif string_option_type == 'thingtype':
             return list(self.thing_types.keys())
         return None
@@ -208,17 +208,14 @@ class Game:
         """Send out game state data relevant to clients."""
 
         def send_thing(offset, thing):
-            offset_pos = (thing.position[1][0] - offset[0],
-                          thing.position[1][1] - offset[1])
+            offset_pos = (thing.position[1] - offset)
             self.io.send('THING_TYPE %s %s' % (thing.id_, thing.type_))
-            self.io.send('THING_POS %s %s' % (thing.id_,
-                                              stringify_yx(offset_pos)))
+            self.io.send('THING_POS %s %s' % (thing.id_, offset_pos))
 
         self.io.send('TURN ' + str(self.world.turn))
         visible_map = self.world.player.get_visible_map()
         offset = self.world.player.get_surroundings_offset()
-        self.io.send('VISIBLE_MAP ' + stringify_yx(offset) + ' '
-                     + stringify_yx(visible_map.size))
+        self.io.send('VISIBLE_MAP %s %s' % (offset, visible_map.size))
         for y, line in visible_map.lines():
             self.io.send('VISIBLE_MAP_LINE %5s %s' % (y, quote(line)))
         visible_things = self.world.player.get_visible_things()
index 0ec953d329befd0dd5e6ec93910e06e78ed69d7a..ee3e9401677e947d0c9fedd64234f9bb94d59ffd 100644 (file)
@@ -1,10 +1,24 @@
 from plomrogue.errors import ArgError
+import collections
+
+
+
+class YX(collections.namedtuple('YX', ('y', 'x'))):
+
+    def __add__(self, other):
+        return YX(self.y + other.y, self.x + other.x)
+
+    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)
 
 
 
 class Map:
 
-    def __init__(self, size=(0, 0)):
+    def __init__(self, size=YX(0, 0)):
         self.size = size
         self.terrain = '?'*self.size_i
 
@@ -20,17 +34,17 @@ class Map:
 
     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[0] * self.size[1]
+        return self.size.y * self.size.x
 
     def set_line(self, y, line):
-        height_map = self.size[0]
-        width_map = self.size[1]
+        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)
@@ -40,11 +54,11 @@ class Map:
                        self.terrain[(y + 1) * width_map:]
 
     def get_position_index(self, yx):
-        return yx[0] * self.size[1] + yx[1]
+        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):
@@ -59,7 +73,6 @@ class Map:
 
     def get_neighbors(self, pos):
         neighbors = {}
-        pos = tuple(pos)
         if not hasattr(self, 'neighbors_to'):
             self.neighbors_to = {}
         if pos in self.neighbors_to:
@@ -82,8 +95,8 @@ class Map:
     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]:
+        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
 
@@ -92,20 +105,20 @@ class Map:
 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)
 
 
 
@@ -116,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)
 
 
 
@@ -146,7 +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[0] / 2) - 0.5
+        self.fov_radius = (self.size.y / 2) - 0.5
         self.terrain = '?' * self.size_i
         self[yx] = '.'
         self.shadow_cones = []
@@ -223,8 +236,8 @@ class FovMap:
         """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]:
+        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
 
@@ -240,7 +253,7 @@ class FovMap:
         # 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:
index 40bd75dd11cdbe77fb09d07c7a65eddfc8c51fa9..a3f7298348cb1cfc29219f1f54c2c6cdf3980b70 100644 (file)
@@ -8,8 +8,3 @@ def quote(string):
         quoted += [c]
     quoted += ['"']
     return ''.join(quoted)
-
-
-def stringify_yx(tuple_):
-    """Transform tuple (y,x) into string 'Y:'+str(y)+',X:'+str(x)."""
-    return 'Y:' + str(tuple_[0]) + ',X:' + str(tuple_[1])
index a8a827f0e00ebd95bebf3eb2148370ef220ed695..13e2c1cf91ba355271959a8ce1aa781f8d073002 100644 (file)
@@ -1,5 +1,6 @@
 import unittest
 from plomrogue.errors import ArgError
+from plomrogue.mapping import YX
 
 
 class Parser:
@@ -88,7 +89,7 @@ class Parser:
             raise ArgError('Wrong number of yx-tuple arguments.')
         y = get_axis_position_from_argument('Y', tokens[0])
         x = get_axis_position_from_argument('X', tokens[1])
-        return (y, x)
+        return YX(y, x)
 
     def argsparse(self, signature, args_tokens):
         """Parse into / return args_tokens as args defined by signature.
index 330eff9b158e41357adbaa91bc207087af0d13c0..3bc0f56ebf50245ee974ba68bbb8644949245118 100644 (file)
@@ -1,5 +1,6 @@
 from plomrogue.errors import GameError
 from plomrogue.misc import quote
+from plomrogue.mapping import YX
 
 
 
@@ -38,10 +39,10 @@ class Task_MOVE(Task):
     argtypes = 'string:direction'
 
     def check(self):
-        test_pos = ((0,0),
-                    self.thing.world.maps[(0,0)].
+        test_pos = (YX(0,0),
+                    self.thing.world.maps[YX(0,0)].
                     move(self.thing.position[1], self.args[0]))
-        if test_pos == ((0,0), None):
+        if test_pos == (YX(0,0), None):
             raise GameError('would move outside map bounds')
         if self.thing.world.maps[test_pos[0]][test_pos[1]] != '.':
             raise GameError('%s would move into illegal terrain' % self.thing.id_)
@@ -50,7 +51,7 @@ class Task_MOVE(Task):
                 raise GameError('%s would move into other thing' % self.thing.id_)
 
     def do(self):
-        self.thing.position = (0,0), self.thing.world.maps[(0,0)].\
+        self.thing.position = YX(0,0), self.thing.world.maps[YX(0,0)].\
                                      move(self.thing.position[1], self.args[0])
 
 
index 13384fc76935d14e328287a34a0716805b75fe6d..1b3a46d3953a3070c9ebc2021f01ca7fc8415840 100644 (file)
@@ -1,11 +1,12 @@
 from plomrogue.errors import GameError
+from plomrogue.mapping import YX
 
 
 
 class ThingBase:
     type_ = '?'
 
-    def __init__(self, world, id_=None, position=((0,0), (0,0))):
+    def __init__(self, world, id_=None, position=(YX(0,0), YX(0,0))):
         self.world = world
         self.position = position
         if id_ is None:
@@ -87,7 +88,7 @@ class ThingAnimate(Thing):
             for pos in dijkstra_map:
                 if visible_map[pos] != '.':
                     continue
-                neighbors = dijkstra_map.get_neighbors(tuple(pos))
+                neighbors = dijkstra_map.get_neighbors(pos)
                 for direction in neighbors:
                     yx = neighbors[direction]
                     if yx is not None and dijkstra_map[yx] < dijkstra_map[pos] - 1:
@@ -111,13 +112,11 @@ class ThingAnimate(Thing):
         target = None
         for t in visible_things:
             if t.type_ == 'human':
-                target = (t.position[1][0] - offset[0],
-                          t.position[1][1] - offset[1])
+                target = t.position[1] - offset
                 break
         if target is not None:
             try:
-                offset_self_pos = (self.position[1][0] - offset[0],
-                                   self.position[1][1] - offset[1])
+                offset_self_pos = self.position[1] - offset
                 target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                        [target])
                 if target_dir is not None:
@@ -143,10 +142,8 @@ class ThingAnimate(Thing):
         food_targets = []
         for t in visible_things:
             if t.type_ == 'food':
-                food_targets += [(t.position[1][0] - offset[0],
-                                  t.position[1][1] - offset[1])]
-        offset_self_pos = (self.position[1][0] - offset[0],
-                           self.position[1][1] - offset[1])
+                food_targets += [t.position[1] - offset]
+        offset_self_pos = self.position[1] - offset
         target_dir = self.move_on_dijkstra_map(offset_self_pos,
                                                food_targets)
         if target_dir:
@@ -216,15 +213,15 @@ class ThingAnimate(Thing):
         self._surroundings_offset = None
 
     def must_fix_indentation(self):
-        return self._radius % 2 != self.position[1][0] % 2
+        return self._radius % 2 != self.position[1].y % 2
 
     def get_surroundings_offset(self):
         if self._surroundings_offset is not None:
             return self._surroundings_offset
         add_line = self.must_fix_indentation()
-        offset_y = self.position[1][0] - self._radius - int(add_line)
-        offset_x = self.position[1][1] - self._radius
-        self._surroundings_offset = (offset_y, offset_x)
+        offset = YX(self.position[1].y - self._radius - int(add_line),
+                    self.position[1].x - self._radius)
+        self._surroundings_offset = offset
         return self._surroundings_offset
 
     def get_surrounding_map(self):
@@ -244,15 +241,15 @@ class ThingAnimate(Thing):
 
         add_line = self.must_fix_indentation()
         self._surrounding_map = self.world.game.\
-                                map_type(size=(self._radius*2+1+int(add_line),
-                                               self._radius*2+1))
+                                map_type(size=YX(self._radius*2+1+int(add_line),
+                                                 self._radius*2+1))
         size = self.world.map_size
         offset = self.get_surroundings_offset()
         for pos in self._surrounding_map:
-            big_y, small_y = pan_and_scan(size[0], pos[0], offset[0])
-            big_x, small_x = pan_and_scan(size[1], pos[1], offset[1])
-            big_yx = (big_y, big_x)
-            small_yx = (small_y, small_x)
+            big_y, small_y = pan_and_scan(size.y, pos.y, offset.y)
+            big_x, small_x = pan_and_scan(size.x, pos.x, offset.x)
+            big_yx = YX(big_y, big_x)
+            small_yx = YX(small_y, small_x)
             self._surrounding_map[pos] = self.world.maps[big_yx][small_yx]
         return self._surrounding_map
 
@@ -265,8 +262,7 @@ class ThingAnimate(Thing):
             if surrounding_map[pos] in {'.', '~'}:
                 m[pos] = '.'
         offset = self.get_surroundings_offset()
-        fov_center = (self.position[1][0] - offset[0],
-                      self.position[1][1] - offset[1])
+        fov_center = self.position[1] - offset
         self._stencil = m.get_fov_map(fov_center)
         return self._stencil
 
@@ -296,12 +292,12 @@ class ThingAnimate(Thing):
         for thing in self.world.things:
             big_pos = thing.position[0]
             small_pos = thing.position[1]
-            pos_y = calc_pos_in_fov(big_pos[0], small_pos[0], offset[0], size[0])
-            pos_x = calc_pos_in_fov(big_pos[1], small_pos[1], offset[1], size[1])
+            pos_y = calc_pos_in_fov(big_pos.y, small_pos.y, offset.y, size.y)
+            pos_x = calc_pos_in_fov(big_pos.x, small_pos.x, offset.x, size.x)
             if pos_y < 0 or pos_x < 0 or\
-               pos_y >= fov_size[0] or pos_x >= fov_size[1]:
+               pos_y >= fov_size.y or pos_x >= fov_size.x:
                 continue
-            if (not thing.in_inventory) and stencil[(pos_y, pos_x)] == '.':
+            if (not thing.in_inventory) and stencil[YX(pos_y, pos_x)] == '.':
                 visible_things += [thing]
         return visible_things
 
@@ -312,7 +308,7 @@ class ThingAnimate(Thing):
                   isinstance(t, ThingItem) and
                   (t.position == self.position or
                    t.position[1] in
-                   self.world.maps[(0,0)].get_neighbors(self.position[1]).values())]:
+                   self.world.maps[YX(0,0)].get_neighbors(self.position[1]).values())]:
             pickable_ids += [t.id_]
         return pickable_ids