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:

HexLayout

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: IntEnum

Enum 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.