Experiment with coloring paths
This commit is contained in:
parent
2b61637d61
commit
a6e13be628
2 changed files with 74 additions and 100 deletions
|
|
@ -1001,28 +1001,42 @@ class Map:
|
||||||
|
|
||||||
return directions, path
|
return directions, path
|
||||||
|
|
||||||
def get_map_display(self, coord, dist=2, mode='scan',
|
def get_visual_range(self, coord, dist=2, mode='nodes',
|
||||||
character='@', max_size=None, return_str=True):
|
character='@',
|
||||||
|
target=None, path_styler="|y{display_symbol}|n",
|
||||||
|
max_size=None,
|
||||||
|
return_str=True):
|
||||||
"""
|
"""
|
||||||
Display the map centered on a point and everything around it within a certain distance.
|
Get a part of the grid centered on a specific point and extended a certain number
|
||||||
|
of nodes or grid points in every direction.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
coord (tuple): (X,Y) in-world coordinate location. If this is not the location
|
coord (tuple): (X,Y) in-world coordinate location. If this is not the location
|
||||||
of a node on the grid, the `character` or the empty-space symbol (by default
|
of a node on the grid, the `character` or the empty-space symbol (by default
|
||||||
an empty space) will be shown.
|
an empty space) will be shown.
|
||||||
dist (int, optional): Number of gridpoints distance to show. Which
|
dist (int, optional): Number of gridpoints distance to show. Which
|
||||||
grid to use depends on the setting of `only_nodes`.
|
grid to use depends on the setting of `only_nodes`. Set to `None` to
|
||||||
|
always show the entire grid.
|
||||||
mode (str, optional): One of 'scan' or 'nodes'. In 'scan' mode, dist measure
|
mode (str, optional): One of 'scan' or 'nodes'. In 'scan' mode, dist measure
|
||||||
number of xy grid points in all directions and doesn't care about if visible
|
number of xy grid points in all directions and doesn't care about if visible
|
||||||
nodes are reachable or not. If 'nodes', distance measure how many linked nodes
|
nodes are reachable or not. If 'nodes', distance measure how many linked nodes
|
||||||
away from the center coordinate to display.
|
away from the center coordinate to display.
|
||||||
character (str, optional): Place this symbol at the `coord` position
|
character (str, optional): Place this symbol at the `coord` position
|
||||||
of the displayed map. The center node' symbol is shown if this is falsy.
|
of the displayed map. The center node' symbol is shown if this is falsy.
|
||||||
|
target (tuple, optional): A target XY coordinate to go to. The path to this
|
||||||
|
(or the beginning of said path, if outside of visual range) will be
|
||||||
|
marked according to `path_style`.
|
||||||
|
path_styler (str or callable, optional): This is use for marking the path
|
||||||
|
found when `path_to_coord` is given. If a string, it accepts a formatting marker
|
||||||
|
`display_symbol` which will be filled with the `display_symbol` of each node/link
|
||||||
|
the path passes through. This allows e.g. to color the path. If a callable, this
|
||||||
|
will receive the MapNode or MapLink object for every step of the path and and
|
||||||
|
must return the suitable string to display at the position of the node/link.
|
||||||
max_size (tuple, optional): A max `(width, height)` to crop the displayed
|
max_size (tuple, optional): A max `(width, height)` to crop the displayed
|
||||||
return to. Make both odd numbers to get a perfect center.
|
return to. Make both odd numbers to get a perfect center.
|
||||||
If unset, display-size can grow up to the full size of the grid.
|
If unset, display-size can grow up to the full size of the grid.
|
||||||
return_str (bool, optional): Return result as an
|
return_str (bool, optional): Return result as an already formatted string
|
||||||
already formatted string.
|
or a 2D list.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str or list: Depending on value of `return_str`. If a list,
|
str or list: Depending on value of `return_str`. If a list,
|
||||||
|
|
@ -1064,18 +1078,20 @@ class Map:
|
||||||
width, height = self.max_x + 1, self.max_y + 1
|
width, height = self.max_x + 1, self.max_y + 1
|
||||||
ix, iy = max(0, min(iX * 2, width)), max(0, min(iY * 2, height))
|
ix, iy = max(0, min(iX * 2, width)), max(0, min(iY * 2, height))
|
||||||
display_map = self.display_map
|
display_map = self.display_map
|
||||||
|
xmin, xmax, ymin, ymax = 0, width - 1, 0, height - 1
|
||||||
|
|
||||||
if dist <= 0 or not self.get_node_from_coord(coord):
|
if dist is None:
|
||||||
|
# show the entire grid
|
||||||
|
gridmap = self.display_map
|
||||||
|
ixc, iyc = ix, iy
|
||||||
|
|
||||||
|
elif dist is None or dist <= 0 or not self.get_node_from_coord(coord):
|
||||||
# There is no node at these coordinates. Show
|
# There is no node at these coordinates. Show
|
||||||
# nothing but ourselves or emptiness
|
# nothing but ourselves or emptiness
|
||||||
return character if character else self.empty_symbol
|
return character if character else self.empty_symbol
|
||||||
|
|
||||||
if mode == 'nodes':
|
elif mode == 'nodes':
|
||||||
# dist measures only full, reachable nodes.
|
# dist measures only full, reachable nodes.
|
||||||
# this requires a series of shortest-path
|
|
||||||
# Steps from on the pre-calulcated grid.
|
|
||||||
# from evennia import set_trace;set_trace()
|
|
||||||
|
|
||||||
points, xmin, xmax, ymin, ymax = self._get_topology_around_coord(coord, dist=dist)
|
points, xmin, xmax, ymin, ymax = self._get_topology_around_coord(coord, dist=dist)
|
||||||
|
|
||||||
ixc, iyc = ix - xmin, iy - ymin
|
ixc, iyc = ix - xmin, iy - ymin
|
||||||
|
|
@ -1086,83 +1102,41 @@ class Map:
|
||||||
for (ix0, iy0) in points:
|
for (ix0, iy0) in points:
|
||||||
gridmap[iy0 - ymin][ix0 - xmin] = display_map[iy0][ix0]
|
gridmap[iy0 - ymin][ix0 - xmin] = display_map[iy0][ix0]
|
||||||
|
|
||||||
# if not self.dist_matrix:
|
elif mode == 'scans':
|
||||||
# self._calculate_path_matrix()
|
# scan-mode - dist measures individual grid points
|
||||||
#
|
|
||||||
# xmin, ymin = width, height
|
xmin, xmax = max(0, ix - dist), min(width, ix + dist + 1)
|
||||||
# xmax, ymax = 0, 0
|
ymin, ymax = max(0, iy - dist), min(height, iy + dist + 1)
|
||||||
# # adjusted center of map section
|
ixc, iyc = ix - xmin, iy - ymin
|
||||||
# ixc, iyc = ix, iy
|
gridmap = [line[xmin:xmax] for line in display_map[ymin:ymax]]
|
||||||
#
|
|
||||||
# center_node = self.get_node_from_coord((iX, iY))
|
|
||||||
# if not center_node:
|
|
||||||
# # there is nothing at this grid location
|
|
||||||
# return character if character else ' '
|
|
||||||
#
|
|
||||||
# # the points list coordinates on the xygrid to show.
|
|
||||||
# points = [(ix, iy)]
|
|
||||||
# node_index_map = self.node_index_map
|
|
||||||
#
|
|
||||||
# # find all reachable nodes within a (weighted) distance of `dist`
|
|
||||||
# for inode, node_dist in enumerate(self.dist_matrix[center_node.node_index]):
|
|
||||||
#
|
|
||||||
# if node_dist > dist:
|
|
||||||
# continue
|
|
||||||
#
|
|
||||||
# # we have a node within 'dist' from us, get, the route to it
|
|
||||||
# node = node_index_map[inode]
|
|
||||||
# _, path = self.get_shortest_path((iX, iY), (node.X, node.Y))
|
|
||||||
# # follow directions to figure out which map coords to display
|
|
||||||
# node0 = node
|
|
||||||
# ix0, iy0 = ix, iy
|
|
||||||
# for path_element in path:
|
|
||||||
# # we don't need the start node since we know it already
|
|
||||||
# if isinstance(path_element, str):
|
|
||||||
# # a direction - this can lead to following
|
|
||||||
# # a longer link-chain chain
|
|
||||||
# for dstep in node0.xy_steps_to_noden[path_element]:
|
|
||||||
# dx, dy = _MAPSCAN[dstep]
|
|
||||||
# ix0, iy0 = ix0 + dx, iy0 + dy
|
|
||||||
# points.append((ix0, iy0))
|
|
||||||
# xmin, ymin = min(xmin, ix0), min(ymin, iy0)
|
|
||||||
# xmax, ymax = max(xmax, ix0), max(ymax, iy0)
|
|
||||||
# else:
|
|
||||||
# # a Mapnode
|
|
||||||
# node0 = path_element
|
|
||||||
# ix0, iy0 = node0.x, node0.y
|
|
||||||
# if (ix0, iy0) != (ix, iy):
|
|
||||||
# points.append((ix0, iy0))
|
|
||||||
# xmin, ymin = min(xmin, ix0), min(ymin, iy0)
|
|
||||||
# xmax, ymax = max(xmax, ix0), max(ymax, iy0)
|
|
||||||
#
|
|
||||||
# ixc, iyc = ix - xmin, iy - ymin
|
|
||||||
# # note - override width/height here since our grid is
|
|
||||||
# # now different from the original for future cropping
|
|
||||||
# width, height = xmax - xmin + 1, ymax - ymin + 1
|
|
||||||
# gridmap = [[" "] * width for _ in range(height)]
|
|
||||||
# for (ix0, iy0) in points:
|
|
||||||
# gridmap[iy0 - ymin][ix0 - xmin] = display_map[iy0][ix0]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# scan-mode (default) - dist measures individual grid points
|
raise MapError(f"Map.get_visual_range 'mode' was '{mode}' "
|
||||||
if dist is None:
|
"- it must be either 'scan' or 'nodes'.")
|
||||||
gridmap = self.display_map
|
|
||||||
ixc, iyc = ix, iy
|
|
||||||
else:
|
|
||||||
left, right = max(0, ix - dist), min(width, ix + dist + 1)
|
|
||||||
bottom, top = max(0, iy - dist), min(height, iy + dist + 1)
|
|
||||||
ixc, iyc = ix - left, iy - bottom
|
|
||||||
gridmap = [line[left:right] for line in display_map[bottom:top]]
|
|
||||||
|
|
||||||
if character:
|
if character:
|
||||||
gridmap[iyc][ixc] = character # correct indexing; it's a list of lines
|
gridmap[iyc][ixc] = character # correct indexing; it's a list of lines
|
||||||
|
|
||||||
if max_size:
|
if max_size:
|
||||||
# crop grid to make sure it doesn't grow too far
|
# crop grid to make sure it doesn't grow too far
|
||||||
max_x, max_y = max_size
|
max_x, max_y = max_size
|
||||||
left, right = max(0, ixc - max_x // 2), min(width, ixc + max_x // 2 + 1)
|
xmin, xmax = max(0, ixc - max_x // 2), min(width, ixc + max_x // 2 + 1)
|
||||||
bottom, top = max(0, iyc - max_y // 2), min(height, iyc + max_y // 2 + 1)
|
ymin, ymax = max(0, iyc - max_y // 2), min(height, iyc + max_y // 2 + 1)
|
||||||
gridmap = [line[left:right] for line in gridmap[bottom:top]]
|
gridmap = [line[xmin:xmax] for line in gridmap[ymin:ymax]]
|
||||||
|
|
||||||
|
if target:
|
||||||
|
# stylize path to target
|
||||||
|
|
||||||
|
def _path_styler(node):
|
||||||
|
return path_styler
|
||||||
|
|
||||||
|
if not callable(path_styler):
|
||||||
|
path_styler = _path_styler
|
||||||
|
|
||||||
|
path, _ = self.get_shortest_path(coord, target)
|
||||||
|
for node_or_link in path[1:]:
|
||||||
|
ix, iy = node_or_link.x, node_or_link.y
|
||||||
|
if xmin <= ix <= xmax and ymin <= iy <= ymax:
|
||||||
|
gridmap[iy - ymin][ix - xmin] = path_styler(node_or_link)
|
||||||
|
|
||||||
if return_str:
|
if return_str:
|
||||||
# we must flip the y-axis before returning the string
|
# we must flip the y-axis before returning the string
|
||||||
|
|
|
||||||
|
|
@ -270,13 +270,13 @@ class TestMap1(TestCase):
|
||||||
((1, 1), "-#\n |", [["-", "#"], [" ", "|"]]),
|
((1, 1), "-#\n |", [["-", "#"], [" ", "|"]]),
|
||||||
|
|
||||||
])
|
])
|
||||||
def test_get_map_display(self, coord, expectstr, expectlst):
|
def test_get_visual_range(self, coord, expectstr, expectlst):
|
||||||
"""
|
"""
|
||||||
Test displaying a part of the map around a central point.
|
Test displaying a part of the map around a central point.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=1, character=None)
|
mapstr = self.map.get_visual_range(coord, dist=1, character=None)
|
||||||
maplst = self.map.get_map_display(coord, dist=1, return_str=False, character=None)
|
maplst = self.map.get_visual_range(coord, dist=1, return_str=False, character=None)
|
||||||
self.assertEqual(expectstr, mapstr)
|
self.assertEqual(expectstr, mapstr)
|
||||||
self.assertEqual(expectlst, maplst[::-1])
|
self.assertEqual(expectlst, maplst[::-1])
|
||||||
|
|
||||||
|
|
@ -287,14 +287,14 @@ class TestMap1(TestCase):
|
||||||
((1, 1), "-@\n |", [["-", "@"], [" ", "|"]]),
|
((1, 1), "-@\n |", [["-", "@"], [" ", "|"]]),
|
||||||
|
|
||||||
])
|
])
|
||||||
def test_get_map_display__character(self, coord, expectstr, expectlst):
|
def test_get_visual_range__character(self, coord, expectstr, expectlst):
|
||||||
"""
|
"""
|
||||||
Test displaying a part of the map around a central point, showing the
|
Test displaying a part of the map around a central point, showing the
|
||||||
character @-symbol in that spot.
|
character @-symbol in that spot.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=1, character='@')
|
mapstr = self.map.get_visual_range(coord, dist=1, character='@')
|
||||||
maplst = self.map.get_map_display(coord, dist=1, return_str=False, character='@')
|
maplst = self.map.get_visual_range(coord, dist=1, return_str=False, character='@')
|
||||||
self.assertEqual(expectstr, mapstr)
|
self.assertEqual(expectstr, mapstr)
|
||||||
self.assertEqual(expectlst, maplst[::-1]) # flip y-axis to match print direction
|
self.assertEqual(expectlst, maplst[::-1]) # flip y-axis to match print direction
|
||||||
|
|
||||||
|
|
@ -306,12 +306,12 @@ class TestMap1(TestCase):
|
||||||
((0, 0), 2, '#-#\n| |\n@-#'),
|
((0, 0), 2, '#-#\n| |\n@-#'),
|
||||||
|
|
||||||
])
|
])
|
||||||
def test_get_map_display__nodes__character(self, coord, dist, expected):
|
def test_get_visual_range__nodes__character(self, coord, dist, expected):
|
||||||
"""
|
"""
|
||||||
Get sub-part of map with node-mode.
|
Get sub-part of map with node-mode.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=dist, mode='nodes', character='@')
|
mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@')
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
||||||
class TestMap2(TestCase):
|
class TestMap2(TestCase):
|
||||||
|
|
@ -360,12 +360,12 @@ class TestMap2(TestCase):
|
||||||
((4, 5), '#-#-@ \n| | \n#---# \n| | \n| #-#'),
|
((4, 5), '#-#-@ \n| | \n#---# \n| | \n| #-#'),
|
||||||
((5, 2), '--# \n | \n #-#\n |\n#---@\n \n--#-#\n | \n#-# '),
|
((5, 2), '--# \n | \n #-#\n |\n#---@\n \n--#-#\n | \n#-# '),
|
||||||
])
|
])
|
||||||
def test_get_map_display__scan__character(self, coord, expected):
|
def test_get_visual_range__scan__character(self, coord, expected):
|
||||||
"""
|
"""
|
||||||
Test showing smaller part of grid, showing @-character in the middle.
|
Test showing smaller part of grid, showing @-character in the middle.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=4, character='@')
|
mapstr = self.map.get_visual_range(coord, dist=4, character='@')
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
||||||
def test_extended_path_tracking__horizontal(self):
|
def test_extended_path_tracking__horizontal(self):
|
||||||
|
|
@ -412,13 +412,13 @@ class TestMap2(TestCase):
|
||||||
((2, 2), 4, (3, 3), ' | \n-@-\n | '),
|
((2, 2), 4, (3, 3), ' | \n-@-\n | '),
|
||||||
((2, 2), 4, (1, 1), '@')
|
((2, 2), 4, (1, 1), '@')
|
||||||
])
|
])
|
||||||
def test_get_map_display__nodes__character(self, coord, dist, max_size, expected):
|
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
|
||||||
"""
|
"""
|
||||||
Get sub-part of map with node-mode.
|
Get sub-part of map with node-mode.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=dist, mode='nodes', character='@',
|
mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
|
||||||
max_size=max_size)
|
max_size=max_size)
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -462,13 +462,13 @@ class TestMap3(TestCase):
|
||||||
'\n # @-# \n |/ \\ \n # #\n / \\ \n# # '),
|
'\n # @-# \n |/ \\ \n # #\n / \\ \n# # '),
|
||||||
((5, 2), 2, None, ' # \n | \n # \n / \\ \n# @\n \\ / \n # \n | \n # ')
|
((5, 2), 2, None, ' # \n | \n # \n / \\ \n# @\n \\ / \n # \n | \n # ')
|
||||||
])
|
])
|
||||||
def test_get_map_display__nodes__character(self, coord, dist, max_size, expected):
|
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
|
||||||
"""
|
"""
|
||||||
Get sub-part of map with node-mode.
|
Get sub-part of map with node-mode.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=dist, mode='nodes', character='@',
|
mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
|
||||||
max_size=max_size)
|
max_size=max_size)
|
||||||
print(f"\n\n{expected}\n\n{mapstr}\n\n{repr(mapstr)}")
|
print(f"\n\n{expected}\n\n{mapstr}\n\n{repr(mapstr)}")
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
||||||
|
|
@ -624,12 +624,12 @@ class TestMap8(TestCase):
|
||||||
((2, 2), 1, None, ' #-o \n | \n# o \n| | \no-o-@-#\n '
|
((2, 2), 1, None, ' #-o \n | \n# o \n| | \no-o-@-#\n '
|
||||||
'| \n o \n | \n # '),
|
'| \n o \n | \n # '),
|
||||||
])
|
])
|
||||||
def test_get_map_display__nodes__character(self, coord, dist, max_size, expected):
|
def test_get_visual_range__nodes__character(self, coord, dist, max_size, expected):
|
||||||
"""
|
"""
|
||||||
Get sub-part of map with node-mode.
|
Get sub-part of map with node-mode.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapstr = self.map.get_map_display(coord, dist=dist, mode='nodes', character='@',
|
mapstr = self.map.get_visual_range(coord, dist=dist, mode='nodes', character='@',
|
||||||
max_size=max_size)
|
max_size=max_size)
|
||||||
print(repr(mapstr))
|
print(repr(mapstr))
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue