Add up/down movement
This commit is contained in:
parent
4224ede1e6
commit
eb7508b36d
2 changed files with 185 additions and 38 deletions
|
|
@ -157,6 +157,9 @@ class MapNode:
|
||||||
# internal use. Set during generation, but is also used for identification of the node
|
# internal use. Set during generation, but is also used for identification of the node
|
||||||
node_index = None
|
node_index = None
|
||||||
|
|
||||||
|
# this should always be left True and avoids inifinite loops during querying.
|
||||||
|
multilink = True
|
||||||
|
|
||||||
def __init__(self, x, y, node_index):
|
def __init__(self, x, y, node_index):
|
||||||
"""
|
"""
|
||||||
Initialize the mapnode.
|
Initialize the mapnode.
|
||||||
|
|
@ -185,7 +188,7 @@ class MapNode:
|
||||||
# this maps
|
# this maps
|
||||||
self.weights = {}
|
self.weights = {}
|
||||||
# lowest direction to a given neighbor
|
# lowest direction to a given neighbor
|
||||||
self.cheapest_to_node = {}
|
self.shortest_route_to_node = {}
|
||||||
# maps the directions (on the xygrid NOT on XYgrid!) taken if stepping
|
# maps the directions (on the xygrid NOT on XYgrid!) taken if stepping
|
||||||
# out from this node in a given direction until you get to the end node.
|
# out from this node in a given direction until you get to the end node.
|
||||||
# This catches eventual longer link chains that would otherwise be lost
|
# This catches eventual longer link chains that would otherwise be lost
|
||||||
|
|
@ -239,10 +242,13 @@ class MapNode:
|
||||||
# links tied together until getting to the node
|
# links tied together until getting to the node
|
||||||
self.xy_steps_to_node[direction] = steps
|
self.xy_steps_to_node[direction] = steps
|
||||||
|
|
||||||
# used for building the shortest path
|
# used for building the shortest path. Note that we store the
|
||||||
cheapest = self.cheapest_to_node.get(node_index, ("", [], _BIG))[2]
|
# aliased link directions here, for quick display by the
|
||||||
if weight < cheapest:
|
# shortest-route solver
|
||||||
self.cheapest_to_node[node_index] = (direction, steps, weight)
|
shortest_route = self.shortest_route_to_node.get(node_index, ("", [], _BIG))[2]
|
||||||
|
if weight < shortest_route:
|
||||||
|
self.shortest_route_to_node[node_index] = (
|
||||||
|
steps[0].direction_aliases.get(direction, direction), steps, weight)
|
||||||
|
|
||||||
def linkweights(self, nnodes):
|
def linkweights(self, nnodes):
|
||||||
"""
|
"""
|
||||||
|
|
@ -301,8 +307,8 @@ class MapLink:
|
||||||
|
|
||||||
- `symbol` (str) - The character to parse from the map into this node. This must be a single
|
- `symbol` (str) - The character to parse from the map into this node. This must be a single
|
||||||
character, with the exception of `\\`.
|
character, with the exception of `\\`.
|
||||||
- `display_symbol` (str or None) - This is what is used to visualize this node later. This symbol
|
- `display_symbol` (str or None) - This is what is used to visualize this node later. This
|
||||||
must still only have a visual size of 1, but you could e.g. use some fancy unicode
|
symbol must still only have a visual size of 1, but you could e.g. use some fancy unicode
|
||||||
character (be aware of encodings to different clients though) or, commonly, add color
|
character (be aware of encodings to different clients though) or, commonly, add color
|
||||||
tags around it. For further customization, the `.get_display_symbol` method receives
|
tags around it. For further customization, the `.get_display_symbol` method receives
|
||||||
the full grid and can return a dynamically determined display symbol. If `None`, the
|
the full grid and can return a dynamically determined display symbol. If `None`, the
|
||||||
|
|
@ -322,6 +328,13 @@ class MapLink:
|
||||||
So for a link chain with default weights, `#---#` would give a total weight of 3. With this
|
So for a link chain with default weights, `#---#` would give a total weight of 3. With this
|
||||||
setting, the weight will be 3 / 3 = 1. That is, for evenly weighted links, the length
|
setting, the weight will be 3 / 3 = 1. That is, for evenly weighted links, the length
|
||||||
of the link doesn't matter.
|
of the link doesn't matter.
|
||||||
|
- `direction_aliases` (dict): When displaying a direction during pathfinding, one may want
|
||||||
|
to display a different 'direction' than the cardinal on-map one. For example 'up' may be
|
||||||
|
visualized on the map as a 'n' movement, but the found path over this link should show
|
||||||
|
as 'u'. In that case, the alias would be `{'n': 'u'}`.
|
||||||
|
- `multilink` (bool): If set, this link accepts links from all directions. It will usually
|
||||||
|
use a custom get_direction to determine what these are based on surrounding topology. This
|
||||||
|
setting is necessary to avoid infinite loops when such multilinks are next to each other.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# link setup
|
# link setup
|
||||||
|
|
@ -341,11 +354,19 @@ class MapLink:
|
||||||
# as {"s": "n", "n": "s"}. The get_direction method can be customized to
|
# as {"s": "n", "n": "s"}. The get_direction method can be customized to
|
||||||
# return something else.
|
# return something else.
|
||||||
directions = {}
|
directions = {}
|
||||||
# this is required for pathfinding. Each weight is defined as {startpos:weight}, where
|
# for displaying the directions during pathfinding, you may want to show a different
|
||||||
|
# direction than the cardinal one. For example, 'up' may be 'n' on the map, but
|
||||||
|
# the direction when moving should be 'u'. This would be a alias {'n': 'u'}.
|
||||||
|
direction_aliases = {}
|
||||||
|
# this is required for pathfinding and contains cardinal directions (n, ne etc) only.
|
||||||
|
# Each weight is defined as {startpos:weight}, where
|
||||||
# the startpos is the direction of the cell (n,ne etc) where the link *starts*. The
|
# the startpos is the direction of the cell (n,ne etc) where the link *starts*. The
|
||||||
# weight is a value > 0, smaller than _BIG. The get_weight method can be
|
# weight is a value > 0, smaller than _BIG. The get_weight method can be
|
||||||
# customized to modify to return something else.
|
# customized to modify to return something else.
|
||||||
weights = {}
|
weights = {}
|
||||||
|
# this shortcuts neighbors trying to figure out if they can connect to this link
|
||||||
|
# - if this is set, they always can (similarly as to a node)
|
||||||
|
multilink = False
|
||||||
|
|
||||||
def __init__(self, x, y):
|
def __init__(self, x, y):
|
||||||
"""
|
"""
|
||||||
|
|
@ -359,8 +380,11 @@ class MapLink:
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
|
|
||||||
|
self.X = x / 2
|
||||||
|
self.Y = y / 2
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"<LinkNode '{self.symbol}' XY=({self.x / 2:g},{self.y / 2:g})>"
|
return f"<LinkNode '{self.symbol}' XY=({self.X:g},{self.Y:g})>"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
@ -393,7 +417,7 @@ class MapLink:
|
||||||
# is perfectly okay to not be linking to a node
|
# is perfectly okay to not be linking to a node
|
||||||
return None, 0, None
|
return None, 0, None
|
||||||
raise MapParserError(f"Link '{self.symbol}' at "
|
raise MapParserError(f"Link '{self.symbol}' at "
|
||||||
f"XY=({self.x / 2:g},{self.y / 2:g}) "
|
f"XY=({self.X:g},{self.Y:g}) "
|
||||||
f"was connected to from the direction {start_direction}, but "
|
f"was connected to from the direction {start_direction}, but "
|
||||||
"is not set up to link in that direction.")
|
"is not set up to link in that direction.")
|
||||||
|
|
||||||
|
|
@ -403,7 +427,7 @@ class MapLink:
|
||||||
next_target = xygrid[end_x][end_y]
|
next_target = xygrid[end_x][end_y]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MapParserError(f"Link '{self.symbol}' at "
|
raise MapParserError(f"Link '{self.symbol}' at "
|
||||||
f"XY=({self.x / 2:g},{self.y / 2, 1:g}) "
|
f"XY=({self.X:g},{self.Y:g}) "
|
||||||
"points to empty space in the direction {end_direction}!")
|
"points to empty space in the direction {end_direction}!")
|
||||||
|
|
||||||
_weight += self.get_weight(start_direction, xygrid, _weight)
|
_weight += self.get_weight(start_direction, xygrid, _weight)
|
||||||
|
|
@ -426,25 +450,22 @@ class MapLink:
|
||||||
_REVERSE_DIRECTIONS[end_direction],
|
_REVERSE_DIRECTIONS[end_direction],
|
||||||
xygrid, _weight=_weight, _linklen=_linklen + 1, _steps=_steps)
|
xygrid, _weight=_weight, _linklen=_linklen + 1, _steps=_steps)
|
||||||
|
|
||||||
def get_visually_connected(self, xygrid, directions=None):
|
def get_linked_neighbors(self, xygrid, directions=None):
|
||||||
"""
|
"""
|
||||||
A helper to get all directions to which there appears to be a
|
A helper to get all directions to which there appears to be a
|
||||||
visual link/node. This does not trace the length of the link and check weights etc.
|
visual link/node. This does not trace the length of the link and check weights etc.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
link (MapLink): Currently active link.
|
|
||||||
xygrid (dict): 2D dict with x,y coordinates as keys.
|
xygrid (dict): 2D dict with x,y coordinates as keys.
|
||||||
directions (list, optional): The directions (n, ne etc) to check
|
directions (list, optional): Only scan in these directions.
|
||||||
visual connection to.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Mapping {direction: node_or_link} wherever such was found.
|
dict: Mapping {direction: node_or_link} wherever such was found.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# if (self.x, self.y) == (4, 8):
|
|
||||||
# from evennia import set_trace;set_trace()
|
|
||||||
if not directions:
|
if not directions:
|
||||||
directions = _REVERSE_DIRECTIONS
|
directions = _REVERSE_DIRECTIONS.keys()
|
||||||
|
|
||||||
links = {}
|
links = {}
|
||||||
for direction in directions:
|
for direction in directions:
|
||||||
dx, dy = _MAPSCAN[direction]
|
dx, dy = _MAPSCAN[direction]
|
||||||
|
|
@ -453,7 +474,7 @@ class MapLink:
|
||||||
# there is is something there, we need to check if it is either
|
# there is is something there, we need to check if it is either
|
||||||
# a map node or a link connecting in our direction
|
# a map node or a link connecting in our direction
|
||||||
node_or_link = xygrid[end_x][end_y]
|
node_or_link = xygrid[end_x][end_y]
|
||||||
if (hasattr(node_or_link, "node_index")
|
if (node_or_link.multilink
|
||||||
or node_or_link.get_direction(direction, xygrid)):
|
or node_or_link.get_direction(direction, xygrid)):
|
||||||
links[direction] = node_or_link
|
links[direction] = node_or_link
|
||||||
return links
|
return links
|
||||||
|
|
@ -519,7 +540,7 @@ class MapLink:
|
||||||
class NSMapLink(MapLink):
|
class NSMapLink(MapLink):
|
||||||
"""Two-way, North-South link"""
|
"""Two-way, North-South link"""
|
||||||
symbol = "|"
|
symbol = "|"
|
||||||
directions = {"s": "n", "n": "s"}
|
directions = {"n": "s", "s": "n"}
|
||||||
|
|
||||||
|
|
||||||
class EWMapLink(MapLink):
|
class EWMapLink(MapLink):
|
||||||
|
|
@ -533,7 +554,6 @@ class NESWMapLink(MapLink):
|
||||||
symbol = "/"
|
symbol = "/"
|
||||||
directions = {"ne": "sw", "sw": "ne"}
|
directions = {"ne": "sw", "sw": "ne"}
|
||||||
|
|
||||||
|
|
||||||
class SENWMapLink(MapLink):
|
class SENWMapLink(MapLink):
|
||||||
"""Two-way, SouthEast-NorthWest link"""
|
"""Two-way, SouthEast-NorthWest link"""
|
||||||
symbol = "\\"
|
symbol = "\\"
|
||||||
|
|
@ -576,11 +596,84 @@ class WEOneWayMapLink(MapLink):
|
||||||
directions = {"w": "e"}
|
directions = {"w": "e"}
|
||||||
|
|
||||||
|
|
||||||
|
class UpMapLink(MapLink):
|
||||||
|
"""
|
||||||
|
Upward-direction. This still uses the xy-grid to fake another level! An up-link can
|
||||||
|
only one two node neighbors (otherwise an error will be raised). If both neighbors are Nodes,
|
||||||
|
then the link will be two way, otherwise it'll be one-way. For clarity, up-down
|
||||||
|
is often shown s-n on the map, but it can be addded in any direction.
|
||||||
|
::
|
||||||
|
|
||||||
|
#
|
||||||
|
u - moving up and down from the two nodes (two-way)
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
| - one-way up from the lower node to the upper
|
||||||
|
u
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
d - (this would be equivalent to the first example but with a longer link)
|
||||||
|
u
|
||||||
|
#
|
||||||
|
|
||||||
|
#u#
|
||||||
|
u - Ok the two up-links don't consider each other
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
u# - invalid.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
symbol = 'u'
|
||||||
|
multilink = True
|
||||||
|
# all movement over this link is 'up', regardless of where on the xygrid we move.
|
||||||
|
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
|
||||||
|
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
|
||||||
|
|
||||||
|
def get_direction(self, start_direction, xygrid):
|
||||||
|
"""
|
||||||
|
Figure out the direction from a specific source direction based on grid topology.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# get all visually connected links
|
||||||
|
if not hasattr(self, '_cached_directions'):
|
||||||
|
# rebuild cache
|
||||||
|
directions = {}
|
||||||
|
neighbors = self.get_linked_neighbors(xygrid)
|
||||||
|
nodes = [direction for direction, neighbor in neighbors.items()
|
||||||
|
if hasattr(neighbor, 'node_index')]
|
||||||
|
|
||||||
|
if len(nodes) == 2:
|
||||||
|
# prefer link to these two nodes
|
||||||
|
for direction in nodes:
|
||||||
|
directions[direction] = _REVERSE_DIRECTIONS[direction]
|
||||||
|
elif len(neighbors) - len(nodes) == 1:
|
||||||
|
for direction in neighbors:
|
||||||
|
directions[direction] = _REVERSE_DIRECTIONS[direction]
|
||||||
|
else:
|
||||||
|
raise MapParserError(
|
||||||
|
f"MapLink '{self.symbol}' at "
|
||||||
|
f"XY=({self.X:g},{self.Y:g}) must have exactly two connections - either "
|
||||||
|
f"two nodes or unambiguous link directions. Found neighbor(s) in directions "
|
||||||
|
f"{list(neighbors.keys())}.")
|
||||||
|
|
||||||
|
self._cached_directions = directions
|
||||||
|
return self._cached_directions.get(start_direction)
|
||||||
|
|
||||||
|
|
||||||
|
class DownMapLink(UpMapLink):
|
||||||
|
"""Works exactly like `UpMapLink` but for the 'down' direction."""
|
||||||
|
symbol = 'd'
|
||||||
|
|
||||||
|
|
||||||
class DynamicMapLink(MapLink):
|
class DynamicMapLink(MapLink):
|
||||||
r"""
|
r"""
|
||||||
Link multiple links together, creating 'knees' and multi-crossings of links.
|
Link multiple links together, creating 'knees' and multi-crossings of links. All such
|
||||||
Remember that this is a link, so user will not 'stop' at it, even if placed on an XY
|
links are two-way. Remember that this is still a link, so user will not 'stop' at it, even if
|
||||||
position!
|
placed on an XY position!
|
||||||
|
|
||||||
The dynamic link has no visual direction so we parse the visual surroundings in the map to see
|
The dynamic link has no visual direction so we parse the visual surroundings in the map to see
|
||||||
if it's obvious what is connected to what. If there are links on cardinally opposite sites,
|
if it's obvious what is connected to what. If there are links on cardinally opposite sites,
|
||||||
|
|
@ -588,36 +681,37 @@ class DynamicMapLink(MapLink):
|
||||||
number of links, an error is raised.
|
number of links, an error is raised.
|
||||||
::
|
::
|
||||||
/
|
/
|
||||||
-o - this is ok, there can only be one path
|
-o - this is ok, there can only be one path, e-ne
|
||||||
|
|
||||||
|
|
|
|
||||||
-o- - this will be assumed to be two links
|
-o- - equivalent to '+', one n-s and one w-e link crossing
|
||||||
|
|
|
|
||||||
|
|
||||||
\|/
|
\|/
|
||||||
-o- - all are passing straight through
|
-o- - all are passing straight through
|
||||||
/|\
|
/|\
|
||||||
|
|
||||||
-o- - w-e pass, other is sw-s
|
-o- - w-e pass straight through, other link is sw-s
|
||||||
/|
|
/|
|
||||||
|
|
||||||
-o - invalid
|
-o - invalid; impossible to know which input goes to which output
|
||||||
/|
|
/|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
symbol = "o"
|
symbol = "o"
|
||||||
|
multilink = True
|
||||||
|
|
||||||
def get_direction(self, start_direction, xygrid):
|
def get_direction(self, start_direction, xygrid):
|
||||||
"""
|
"""
|
||||||
Dynamically determine the directions-dict based on the grid topology.
|
Dynamically determine the direction based on a source direction and grid topology.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# get all visually connected links
|
# get all visually connected links
|
||||||
if not hasattr(self, '_cached_directions'):
|
if not hasattr(self, '_cached_directions'):
|
||||||
# try to get from cache where possible
|
# try to get from cache where possible
|
||||||
directions = {}
|
directions = {}
|
||||||
unhandled_links = list(self.get_visually_connected(xygrid).keys())
|
unhandled_links = list(self.get_linked_neighbors(xygrid).keys())
|
||||||
|
|
||||||
# get all straight lines (n-s, sw-ne etc) we can trace through
|
# get all straight lines (n-s, sw-ne etc) we can trace through
|
||||||
# the dynamic link and remove them from the unhandled_links list
|
# the dynamic link and remove them from the unhandled_links list
|
||||||
|
|
@ -636,8 +730,8 @@ class DynamicMapLink(MapLink):
|
||||||
if n_unhandled != 2:
|
if n_unhandled != 2:
|
||||||
links = ", ".join(unhandled_links)
|
links = ", ".join(unhandled_links)
|
||||||
raise MapParserError(
|
raise MapParserError(
|
||||||
f"Dynamic Link '{self.symbol}' at "
|
f"MapLink '{self.symbol}' at "
|
||||||
f"XY=({self.x / 2:g},{self.y / 2:g}) cannot determine "
|
f"XY=({self.X:g},{self.Y:g}) cannot determine "
|
||||||
f"how to connect in/out directions {links}.")
|
f"how to connect in/out directions {links}.")
|
||||||
|
|
||||||
directions[unhandled_links[0]] = unhandled_links[1]
|
directions[unhandled_links[0]] = unhandled_links[1]
|
||||||
|
|
@ -663,6 +757,8 @@ DEFAULT_LEGEND = {
|
||||||
"<": EWOneWayMapLink,
|
"<": EWOneWayMapLink,
|
||||||
">": WEOneWayMapLink,
|
">": WEOneWayMapLink,
|
||||||
"o": DynamicMapLink,
|
"o": DynamicMapLink,
|
||||||
|
"u": UpMapLink,
|
||||||
|
"d": DownMapLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
|
@ -911,7 +1007,7 @@ class Map:
|
||||||
mapnode_or_link_class = self.legend.get(char)
|
mapnode_or_link_class = self.legend.get(char)
|
||||||
if not mapnode_or_link_class:
|
if not mapnode_or_link_class:
|
||||||
raise MapParserError(
|
raise MapParserError(
|
||||||
f"Symbol '{char}' on XY=({ix / 2, 1:g},{iy / 2, 1:g}) "
|
f"Symbol '{char}' on XY=({ix / 2:g},{iy / 2:g}) "
|
||||||
"is not found in LEGEND."
|
"is not found in LEGEND."
|
||||||
)
|
)
|
||||||
if hasattr(mapnode_or_link_class, "node_index"):
|
if hasattr(mapnode_or_link_class, "node_index"):
|
||||||
|
|
@ -920,7 +1016,7 @@ class Map:
|
||||||
|
|
||||||
if not (even_iy and ix % 2 == 0):
|
if not (even_iy and ix % 2 == 0):
|
||||||
raise MapParserError(
|
raise MapParserError(
|
||||||
f"Symbol '{char}' on XY=({ix / 2, 1:g},{iy / 2, 1:g}) marks a "
|
f"Symbol '{char}' on XY=({ix / 2:g},{iy / 2:g}) marks a "
|
||||||
"MapNode but is located between integer (X,Y) positions (only "
|
"MapNode but is located between integer (X,Y) positions (only "
|
||||||
"Links can be placed between coordinates)!")
|
"Links can be placed between coordinates)!")
|
||||||
|
|
||||||
|
|
@ -1081,10 +1177,10 @@ class Map:
|
||||||
inextnode = pathfinding_routes[istartnode, inextnode]
|
inextnode = pathfinding_routes[istartnode, inextnode]
|
||||||
nextnode = node_index_map[inextnode]
|
nextnode = node_index_map[inextnode]
|
||||||
|
|
||||||
cheapest_links_to = nextnode.cheapest_to_node[path[-1].node_index]
|
shortest_route_to = nextnode.shortest_route_to_node[path[-1].node_index]
|
||||||
|
|
||||||
directions.append(cheapest_links_to[0])
|
directions.append(shortest_route_to[0])
|
||||||
path.extend(cheapest_links_to[1] + [nextnode])
|
path.extend(shortest_route_to[1] + [nextnode])
|
||||||
|
|
||||||
# we have the path - reverse to get the correct order
|
# we have the path - reverse to get the correct order
|
||||||
path = path[::-1]
|
path = path[::-1]
|
||||||
|
|
|
||||||
|
|
@ -231,12 +231,37 @@ o-o-#-# o
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
|
MAP9 = r"""
|
||||||
|
+ 0 1 2 3
|
||||||
|
|
||||||
|
3 #-# #-#
|
||||||
|
d d |
|
||||||
|
2 | | |
|
||||||
|
u | u
|
||||||
|
1 #-#-#-#
|
||||||
|
u d
|
||||||
|
0 #u# #d#
|
||||||
|
|
||||||
|
+ 0 1 2 3
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
MAP9_DISPLAY = r"""
|
||||||
|
#-# #-#
|
||||||
|
d d |
|
||||||
|
| | |
|
||||||
|
u | u
|
||||||
|
#-#-#-#
|
||||||
|
u d
|
||||||
|
#u# #d#
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
class TestMap1(TestCase):
|
class TestMap1(TestCase):
|
||||||
"""
|
"""
|
||||||
Test the Map class with a simple 4-node map
|
Test the Map class with a simple 4-node map
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.map = mapsystem.Map({"map": MAP1})
|
self.map = mapsystem.Map({"map": MAP1})
|
||||||
|
|
||||||
|
|
@ -657,3 +682,29 @@ class TestMap8(TestCase):
|
||||||
character='@',
|
character='@',
|
||||||
max_size=max_size)
|
max_size=max_size)
|
||||||
self.assertEqual(expected, mapstr)
|
self.assertEqual(expected, mapstr)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMap9(TestCase):
|
||||||
|
"""
|
||||||
|
Test the Map class with a simple 4-node map
|
||||||
|
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
self.map = mapsystem.Map({"map": MAP9})
|
||||||
|
|
||||||
|
def test_str_output(self):
|
||||||
|
"""Check the display_map"""
|
||||||
|
stripped_map = "\n".join(line.rstrip() for line in str(self.map).split('\n'))
|
||||||
|
self.assertEqual(MAP9_DISPLAY, stripped_map)
|
||||||
|
|
||||||
|
@parameterized.expand([
|
||||||
|
((0, 0), (0, 1), ('u',)),
|
||||||
|
((0, 0), (1, 0), ('u',)),
|
||||||
|
])
|
||||||
|
def test_shortest_path(self, startcoord, endcoord, expected_directions):
|
||||||
|
"""
|
||||||
|
test shortest-path calculations throughout the grid.
|
||||||
|
|
||||||
|
"""
|
||||||
|
directions, _ = self.map.get_shortest_path(startcoord, endcoord)
|
||||||
|
self.assertEqual(expected_directions, tuple(directions))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue