HexGrid
- class w9_pathfinding.envs.HexGrid
A 2D grid environment with hexagonal tiles with support for obstacles, weighted traversal, edge-wrapping and different hexagonal layouts (flat-topped and pointy-topped).
The grid can be initialized either with an explicit size (width and height) or from a nested list of weights.
- Parameters:
weights (nested list of float, optional) –
A grid-shaped array representing movement cost to enter each node. Each value must be a non-negative float or exactly -1.
A positive value indicates the movement cost for that node.
A value of -1 marks the node as an obstacle (impassable).
width (int, optional) – Width of the grid. Required if weights is not provided.
height (int, optional) – Height of the grid. Required if weights is not provided.
layout (HexLayout, default HexLayout.odd_r) – Orientation and offset pattern of the hex grid. Determines whether the grid uses pointy-top or flat-top hexes and how odd/even rows or columns are offset.
passable_left_right_border (bool, default False) – Whether the grid wraps horizontally (left/right edges connect). This wrapping is not supported for odd-width grids with flat-top layout.
passable_up_down_border (bool, default False) – Whether the grid wraps vertically (top/bottom edges connect). This wrapping is not supported for odd-height grids with pointy-top layout.
pause_weights (nested list of float, optional) –
A grid-shaped array representing the cost of pausing (waiting in place) at each node. Each value must be a non-negative float or exactly -1.
A non-negative value indicates the cost to pause at that node.
A value of -1 means pausing is not allowed at that node.
edge_collision (bool, default False) – Whether to enable edge collision checks. If set to True, prevents two agents from using the same edge simultaneously, even if they are moving in opposite directions. This helps avoid edge conflicts (e.g. node swapping) in multi-agent pathfinding scenarios.
Examples
Create a 3x3 hex grid with one obstacle in the middle:
>>> grid = HexGrid(width=3, height=3) # all weights will default to 1.0 >>> grid.add_obstacle((1, 1))
Create a 3x3 hex grid with custom weights:
>>> grid = HexGrid( ... [ ... [1, 2, 3], ... [0.1, 0.2, 0.3], ... [-1, -1, -1], # -1 means obstacles; this row is impassable ... ] ... )
- add_obstacle(node)
Mark the specified node as an obstacle.
- Parameters:
node (tuple of int) – The coordinate to mark as an obstacle.
- Raises:
ValueError – If the node is outside the bounds of the grid.
- adjacent(v1, v2) bool
Check whether two nodes are directly connected.
- Parameters:
v1 (node) – First node.
v2 (node) – Second node.
- Returns:
True if there is a direct edge from v1 to v2.
- Return type:
bool
- Raises:
ValueError – If either v1 or v2 is not a valid node in the environment.
- calculate_cost(path) double
Calculate the total cost of a given path through the environment.
If the path is invalid (e.g. contains non-adjacent nodes), this will return -1.
- Parameters:
path (iterable of nodes) – A sequence of nodes representing the path to evaluate.
- Returns:
Total cost of traversing the path, or -1 if the path is invalid.
- Return type:
float
- Raises:
ValueError – If one of the nodes in the path is not a valid node in the environment.
- contains(node) bool
Check if the environment contains a given node.
- Parameters:
node – The node to check.
- Returns:
True if the node is in the environment, False otherwise.
- Return type:
bool
- edge_collision
Whether edge collision checks are enabled.
- find_components()
Find connected components.
- Returns:
List of components, each as a list of nodes.
- Return type:
List[List[node]]
- get_neighbors(node, include_self=False) list
Get neighboring nodes of a given node, along with the cost of moving to each.
Each neighbor is returned as a tuple of (neighbor_node, cost). For example: [(n1, 1.0), (n2, 2.5)]
- Parameters:
node – The target node.
include_self (bool, default False) – Whether to include the node itself if there is an self loop.
- Returns:
List of neighbors with movement costs.
- Return type:
List[Tuple[node, float]]
- Raises:
ValueError – If the node is not a valid node in the environment.
- get_pause_weight(node) double
Get the pause cost at a specific node.
- Parameters:
node (tuple of int) – The coordinate to query.
- Returns:
The cost of remaining at the specified node.
- Return type:
float
- Raises:
ValueError – If the node is outside the bounds of the grid.
- get_weight(node) double
Get the movement cost to enter a node in the grid.
- Parameters:
node (tuple of int) – The coordinate to query.
- Returns:
The movement cost to enter the specified node.
- Return type:
float
- Raises:
ValueError – If the node is outside the bounds of the grid.
- has_obstacle(node) bool
Check whether the specified node is marked as an obstacle.
- Parameters:
node (tuple of int) – The grid coordinate to check.
- Returns:
True if the node is an obstacle; False otherwise.
- Return type:
bool
- Raises:
ValueError – If the node is outside the bounds of the grid.
- height
Number of rows in the grid.
- is_flat_top_layout() bool
Whether the grid layout is a pointy-top (row-aligned) hex layout.
- is_pointy_top_layout() bool
Whether the grid layout is a flat-top (column-aligned) hex layout.
- is_valid_path(path) bool
Check if a given path is valid within the environment.
- Parameters:
path (iterable of nodes) – A sequence of nodes representing the path
- Returns:
True if the path is valid, False otherwise.
- Return type:
bool
- Raises:
ValueError – If one of the nodes in the path is not a valid node in the environment.
- layout
Hex layout of the grid.
- Returns:
Enum value indicating the orientation and offset system.
- Return type:
- obstacle_map
Get a binary map of obstacles in the grid.
- Returns:
A grid-shaped nested structure where each cell contains:
1 if the corresponding node is an obstacle (weight = -1)
0 otherwise
- Return type:
array-like
- passable_left_right_border
Whether the grid wraps horizontally (left/right edges connect).
- passable_up_down_border
Whether the grid wraps vertically (top/bottom edges connect).
- pause_weights
A grid-shaped array representing the cost of pausing (waiting in place) at each node
Notes
This is a read-only snapshot of internal weights; modifying it won’t change the grid.
- remove_obstacle(node)
Remove the obstacle status from the specified node.
- Parameters:
node (tuple of int) – The coordinate to unmark as an obstacle.
- Raises:
ValueError – If the node is outside the bounds of the grid.
- shape
Shape of the grid, (height, width).
- size
Total number of nodes in the environment.
- to_dict()
Convert environment settings to a serializable dictionary.
- Returns:
Dictionary of environment configuration options.
- Return type:
dict
- update_weight(node, new_value)
Update the movement cost (weight) of a specific node in the grid.
- Parameters:
node (tuple of int) – The coordinate whose weight should be updated.
new_value (float) – The new cost value for moving into this node.
- Raises:
ValueError – If the node is outside the bounds of the grid
ValueError – If new_value is negative and not equal to -1.
- weights
A grid-shaped array representing movement cost to enter each node.
Notes
This is a read-only snapshot of internal weights; modifying it won’t change the grid.
- width
Number of columns in the grid.
- class w9_pathfinding.envs.HexLayout(value)
Bases:
IntEnumEnum representing hex grid layouts, defined by orientation and offset pattern.
Layout types:
‘r’ (row-based): pointy-top hexes aligned in rows
‘q’ (column-based): flat-top hexes aligned in columns
‘odd’: offset applies to odd rows or columns
‘even’: offset applies to even rows or columns
Modes:
odd_r (0): Pointy-top hexes, odd rows are offset to the right:
/ \ / \ / \ / \ / \ / \ / \ / \ | (0,0) | (1,0) | (2,0) | (3,0) | | (x,y) | | | | \ / \ / \ / \ / \ \ / \ / \ / \ / \ | (0,1) | (1,1) | (2,1) | (3,1) | | | | | | / \ / \ / \ / \ / / \ / \ / \ / \ / | (0,2) | (1,2) | (2,2) | (3,2) | | | | | | \ / \ / \ / \ / \ / \ / \ / \ /
even_r (1): Pointy-top hexes, even rows are offset to the right:
/ \ / \ / \ / \ / \ / \ / \ / \ | (0,0) | (1,0) | (2,0) | (3,0) | | (x,y) | | | | / \ / \ / \ / \ / / \ / \ / \ / \ / | (0,1) | (1,1) | (2,1) | (3,1) | | | | | | \ / \ / \ / \ / \ \ / \ / \ / \ / \ | (0,2) | (1,2) | (2,2) | (3,2) | | | | | | \ / \ / \ / \ / \ / \ / \ / \ /
odd_q (2): Flat-top hexes, odd columns are offset downward:
_ _ _ _ / \ / \ / (0,0) \ _ _ / (2,0) \ _ _ \ (x,y) / \ / \ \ _ _ / (1,0) \ _ _ / (3,0) \ / \ / \ / / (0,1) \ _ _ / (2,1) \ _ _ / \ / \ / \ \ _ _ / (1,1) \ _ _ / (3,1) \ / \ / \ / / (0,2) \ _ _ / (2,2) \ _ _ / \ / \ / \ \ _ _ / (1,2) \ _ _ / (3,2) \ \ / \ / \ _ _ / \ _ _ /
even_q (3): Flat-top hexes, even columns are offset downward:
_ _ _ _ / \ / \ _ _ / (1,0) \ _ _ / (3,0) \ / \ / \ / / (0,0) \ _ _ / (2,0) \ _ _ / \ (x,y) / \ / \ \ _ _ / (1,1) \ _ _ / (3,1) \ / \ / \ / / (0,1) \ _ _ / (2,1) \ _ _ / \ / \ / \ \ _ _ / (1,2) \ _ _ / (3,2) \ / \ / \ / / (0,2) \ _ _ / (2,2) \ _ _ / \ / \ / \ _ _ / \ _ _ /
- odd_r = HexLayout.odd_r
Pointy-top hexes, odd rows are offset to the right
- even_r = HexLayout.even_r
Pointy-top hexes, even rows are offset to the right
- odd_q = HexLayout.odd_q
Flat-top hexes, odd columns are offset downward
- even_q = HexLayout.even_q
Flat-top hexes, even columns are offset downward
- is_pointy_top() bool
Return whether this layout is a pointy-top (row-aligned) hex layout.
- is_flat_top() bool
Return whether this layout is a flat-top (column-aligned) hex layout.