home · contact · privacy
Don't provide space for unused input line.
[plomrogue2-experiments] / new2 / plomrogue / mapping.py
1 import collections
2 from plomrogue.errors import ArgError
3
4
5
6 class YX(collections.namedtuple('YX', ('y', 'x'))):
7
8     def __add__(self, other):
9         return YX(self.y + other.y, self.x + other.x)
10
11     def __sub__(self, other):
12         return YX(self.y - other.y, self.x - other.x)
13
14     def __str__(self):
15         return 'Y:%s,X:%s' % (self.y, self.x)
16
17
18
19 class MapGeometry():
20
21     def __init__(self, size):
22         self.size = size
23
24     def get_directions(self):
25         directions = []
26         for name in dir(self):
27             if name[:5] == 'move_':
28                 directions += [name[5:]]
29         return directions
30
31     def get_neighbors(self, pos):
32         neighbors = {}
33         for direction in self.get_directions():
34             neighbors[direction] = self.move(pos, direction)
35         return neighbors
36
37     def move(self, start_pos, direction):
38         mover = getattr(self, 'move_' + direction)
39         target = mover(start_pos)
40         if target.y < 0 or target.x < 0 or \
41                 target.y >= self.size.y or target.x >= self.size.x:
42             return None
43         return target
44
45
46
47 class MapGeometryWithLeftRightMoves(MapGeometry):
48
49     def move_LEFT(self, start_pos):
50         return YX(start_pos.y, start_pos.x - 1)
51
52     def move_RIGHT(self, start_pos):
53         return YX(start_pos.y, start_pos.x + 1)
54
55
56
57 class MapGeometrySquare(MapGeometryWithLeftRightMoves):
58
59     def move_UP(self, start_pos):
60         return YX(start_pos.y - 1, start_pos.x)
61
62     def move_DOWN(self, start_pos):
63         return YX(start_pos.y + 1, start_pos.x)
64
65
66
67 class Map():
68
69     def __init__(self, map_size):
70         self.size = map_size
71         self.terrain = '.' * self.size_i
72
73     def __getitem__(self, yx):
74         return self.terrain[self.get_position_index(yx)]
75
76     def __setitem__(self, yx, c):
77         pos_i = self.get_position_index(yx)
78         if type(c) == str:
79             self.terrain = self.terrain[:pos_i] + c + self.terrain[pos_i + 1:]
80         else:
81             self.terrain[pos_i] = c
82
83     @property
84     def size_i(self):
85         return self.size.y * self.size.x
86
87     def set_line(self, y, line):
88         height_map = self.size.y
89         width_map = self.size.x
90         if y >= height_map:
91             raise ArgError('too large row number %s' % y)
92         width_line = len(line)
93         if width_line != width_map:
94             raise ArgError('map line width %s unequal map width %s' % (width_line, width_map))
95         self.terrain = self.terrain[:y * width_map] + line +\
96                        self.terrain[(y + 1) * width_map:]
97
98     def get_position_index(self, yx):
99         return yx.y * self.size.x + yx.x
100
101     def lines(self):
102         width = self.size.x
103         for y in range(self.size.y):
104             yield (y, self.terrain[y * width:(y + 1) * width])