Skip to main content

slackwater-lattice

tests version python

Exact integer geometry on the Eisenstein A₂ hexagonal lattice — the densest packing of circles in a plane. Every point has exactly six equidistant neighbors. No privileged axis. No floating-point drift. This package provides Eisenstein integer arithmetic, build placement with collision detection, and A* pathfinding on the hexagonal neighbor graph.

Installation

pip install slackwater-lattice

Mathematical Foundation

Eisenstein integers are ℤ[ω] where ω = e^(2πi/3) = −1/2 + i√3/2. They form a triangular/hexagonal lattice in the complex plane.

Coordinate system: A point (a, b) in Eisenstein coordinates maps to Cartesian:

x = (a − b/2) · scale
y = b · (√3/2) · scale

Norm (squared distance from origin):

N(a + bω) = a² − ab + b²

This is always a non-negative integer. All arithmetic is exact — no floating point, no drift.

Six neighbor directions (unit norm elements):

Direction Offset Cartesian
+1 (1, 0) East
−1 (−1, 0) West
+ω (0, 1) Northeast
−ω (0, −1) Southwest
+(1+ω) (1, 1) Southeast
−(1+ω) (−1, −1) Northwest

API Reference

EisensteinInteger

from slackwater_lattice import EisensteinInteger

EisensteinInteger(a: int, b: int)

An exact point on the A₂ lattice. Represents the value a + bω. Frozen dataclass — hashable, comparable.

Arithmetic operators:

Operator Signature Formula
+ (ei) -> ei (a+c, b+d)
− (ei) -> ei (a−c, b−d)
* (ei) -> ei (ac−bd, ad+bc−bd)
conjugate() () -> ei (a−b, −b)
norm() () -> int a² − ab + b²
− (unary) () -> ei (−a, −b)

Coordinate conversion:

ei.to_cartesian(scale: float = 1.0) -> tuple[float, float]
EisensteinInteger.from_cartesian(x: float, y: float, scale: float = 1.0) -> EisensteinInteger

The from_cartesian method rounds to the nearest lattice point. This is the snapping algorithm — continuous space → discrete lattice. It is deterministic and exact.

Lattice operations:

ei.neighbors() -> list[EisensteinInteger]           # 6 equidistant neighbors
ei.rings(radius: int) -> list[EisensteinInteger]     # all points within hex distance
ei.is_unit() -> bool                                  # norm == 1?
ei.is_zero() -> bool                                  # a==0 and b==0?

Module-level functions:

snap(x: float, z: float, scale: float = 1.0) -> EisensteinInteger
distance(a: EisensteinInteger, b: EisensteinInteger) -> int        # squared Euclidean
hex_distance(a: EisensteinInteger, b: EisensteinInteger) -> int    # graph steps
midpoint_region(a: EisensteinInteger, b: EisensteinInteger) -> list[EisensteinInteger]

Hex distance formula:

if da·db ≥ 0:  d = max(|da|, |db|)     # same sector
else:          d = |da| + |db|          # opposite sectors

BuildPlacement

from slackwater_lattice import BuildPlacement, PlacementError

BuildPlacement(
    scale: float = 4.0,    # world units per lattice unit
)

Manages occupied lattice points for a build. Collision detection is exact integer comparison — O(1) hash lookup, no tolerance bands.

Snapping:

bp.snap_position(x: float, z: float) -> EisensteinInteger
bp.snap_rotation(rotation_deg: float) -> int    # nearest 60° increment

Collision and reservation:

bp.check_collision(lattice_point: EisensteinInteger) -> bool
bp.check_region_clear(center: EisensteinInteger, radius: int = 1) -> bool
bp.reserve(lattice_point: EisensteinInteger, meta: dict | None = None) -> EisensteinInteger
bp.release(lattice_point: EisensteinInteger) -> bool
bp.place(x: float, z: float, meta: dict | None = None) -> EisensteinInteger  # snap + reserve

reserve() raises PlacementError on collision. place() is the combined snap-and-reserve convenience.

Queries:

bp.nearest_free(point: EisensteinInteger, max_radius: int = 20) -> EisensteinInteger | None
bp.occupied_neighbors(point: EisensteinInteger) -> list[EisensteinInteger]
bp.free_neighbors(point: EisensteinInteger) -> list[EisensteinInteger]
bp.boundary_points() -> list[EisensteinInteger]    # frontier of the build
bp.footprint_area() -> int                          # count of occupied points
bp.diameter() -> int                                # max hex distance between any two points

Supports in operator, len(), and iteration.

LatticePathfinder

from slackwater_lattice import LatticePathfinder, LatticePath

LatticePathfinder(
    placement: BuildPlacement,
    allow_through_occupied: bool = False,
)

A* pathfinder on the Eisenstein lattice. Uses hex_distance as the heuristic — admissible and consistent on the neighbor graph, guaranteeing optimal paths.

Methods:

pf.find_path(
    start: EisensteinInteger,
    goal: EisensteinInteger,
    max_steps: int = 10_000,
) -> LatticePath | None

Returns the shortest path through free lattice points, or None if unreachable.

pf.find_all_paths(start, goal, max_paths: int = 5) -> list[LatticePath]
pf.reachable(start, max_distance: int = 20) -> dict[EisensteinInteger, int]

find_all_paths uses a simplified Yen's algorithm for k-shortest paths. reachable does BFS within max_distance steps.

LatticePath:

@dataclass
class LatticePath:
    points: list[EisensteinInteger]
    
    length() -> int      # number of steps (edges)
    is_empty() -> bool   # single point or less

Supports iteration and indexing.

Examples

Basic lattice arithmetic

from slackwater_lattice import EisensteinInteger, distance, hex_distance

z = EisensteinInteger(3, 1)
print(z.norm())            # 7  (9 - 3 + 1)
print(z.to_cartesian(4.0)) # (10.0, 3.464...)

neighbors = z.neighbors()  # 6 points at distance 1

Snapping world positions to the lattice

from slackwater_lattice import BuildPlacement

bp = BuildPlacement(scale=4.0)
point = bp.place(10.5, 3.2)
print(point)  # nearest lattice point to (10.5, 3.2) at scale 4

# Collision-free placement
free = bp.nearest_free(point)

Pathfinding around obstacles

from slackwater_lattice import EisensteinInteger, BuildPlacement, LatticePathfinder

bp = BuildPlacement()
# Build a wall
for i in range(-2, 3):
    bp.reserve(EisensteinInteger(0, i))

pf = LatticePathfinder(placement=bp)
path = pf.find_path(EisensteinInteger(-3, 0), EisensteinInteger(3, 0))
print(path)         # LatticePath(E(-3) → E(-2) → ... → E(3))
print(path.length()) # hex-optimal, avoids all wall points

License

MIT

Metadata

Release files for slackwater-lattice 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for slackwater-lattice 0.1.1
File Size Uploaded Provenance Actions
slackwater_lattice-0.1.1.tar.gz 23.1 kB Without provenance Details for slackwater_lattice-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for slackwater-lattice 0.1.1
File Interpreter ABI Platform Actions
slackwater_lattice-0.1.1-py3-none-any.whl Python 3 none any Details for slackwater_lattice-0.1.1-py3-none-any.whl

Total release size: 38.6 kB

Release files / slackwater_lattice-0.1.1.tar.gz

Download URL slackwater_lattice-0.1.1.tar.gz
Size 23.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c6b58980679554ba390c3b198a348e2c2be40ef2d6713e5d6224d4362618130f
BLAKE2b-256 checksum
How to use checksums
b4992e974b78fa758d161271379974f3a4a85dc4df2b8e09bf5364e2d2796f97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / slackwater_lattice-0.1.1-py3-none-any.whl

Download URL slackwater_lattice-0.1.1-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
546d8af30c4195d643a6cfd91bacc89a0c8938dfbad9edab3d2cb92f445bea56
BLAKE2b-256 checksum
How to use checksums
4677a3d5c43b9c4a1222ac8da5373832ab4f4e3648f1a119069d9b532361ac4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for slackwater-lattice 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page