Hexo Engine
Hexo is a Python engine for the Hexo game played on an infinite hex grid.
The goal of this repository is to provide a clean, reusable engine API (similar in spirit to python-chess) so others can build bots, analysis tools, and frontends without re-implementing game logic.
Game rules are documented in RULES.md. Agent handoff context is documented in AGENT_CONTEXT.md.
Features
- Deterministic game engine with strict rule validation
- Infinite hex-grid coordinate model
- Opening and turn rules enforced by the engine
- Win detection (connect 6 on any hex axis)
- Undo support for search algorithms
Installation
Requirements
- UV package manager
Clone the repository
git clone https://github.com/<your-org>/hexo.git
cd hexo
Initialize your environment
uv sync
uv run pre-commit install
API
Public entry point is the Hexo class.
Hexo.new(config=None) -> Hexo: create a new game withP1already placed at(0, 0).Hexo.from_state(state, config=None) -> Hexo: restore a game from serialized state.game.to_state() -> dict: serialize committed turns and any in-progress partial turn.game.turn() -> Player: return the player currently placing stones.game.status() -> GameStatus: returnONGOING,P1_WON, orP2_WON.game.moves_left_in_turn() -> int: return remaining moves in current turn (2or1).game.pending_moves() -> tuple[Coord, ...]: return moves already made in the current turn.game.is_legal_move(coord) -> tuple[bool, str | None]: validate one submove.game.legal_moves -> Collection[Coord]: property that returns legal single-move candidates as a live iterable view.game.push(coord) -> TurnRecord | None: play one move; returnsNoneif turn is still partial, orTurnRecordwhen the turn completes (or wins early).game.is_legal(move) -> tuple[bool, str | None]: validate a full 2-stone move (only when no partial turn is active).game.play(move) -> TurnRecord: convenience wrapper that places two stones in sequence.game.undo() -> TurnRecord: undo the last placement (works for both partial and completed turns).game.at(coord) -> Player | None: inspect occupancy at a coordinate.game.board() -> dict[Coord, Player]: get a snapshot of all occupied coordinates.
Notes:
Hexo.new()starts withP1already placed at(0, 0).- Every played turn is a 2-stone move.
Quickstart
from hexo import GameStatus, Hexo
def move_key(coord: tuple[int, int]) -> tuple[int, int, int]:
# Deterministic "closest to center" move ordering.
return (
abs(coord[0]) + abs(coord[1]) + abs(coord[0] + coord[1]),
coord[0],
coord[1],
)
def play_turn(game: Hexo):
first = min(game.legal_moves, key=move_key)
record = game.push(first)
if record is not None: # win can happen on first placement
return record
second = min(game.legal_moves, key=move_key)
return game.push(second)
game = Hexo.new() # P1 center stone is pre-applied at (0, 0)
for turn_no in range(1, 6):
if game.status() is not GameStatus.ONGOING:
break
record = play_turn(game)
print(f"turn {turn_no}: {record.player.name} {record.placements} won={record.won}")
print("stones on board:", len(game.board()))
print("next player:", game.turn().name)
# Useful for bot search trees: snapshot, restore, undo
snapshot = game.to_state()
restored = Hexo.from_state(snapshot)
affected = restored.undo()
print("undo affected turn:", affected)
Tests, linting and formatting
uv run pytest
uvx ruff check . --fix
uvx ruff format .
Run all hooks manually:
uv run pre-commit run --all-files
Benchmarks
Benchmarking uses pytest-benchmark and is kept separate from normal tests.
Run benchmarks:
uv run pytest benchmarks --benchmark-only
Save a baseline:
uv run pytest benchmarks --benchmark-only --benchmark-save=baseline
Compare with a saved baseline:
uv run pytest benchmarks --benchmark-only --benchmark-compare=baseline
Contributing
See CONTRIBUTING.md for:
- issue reporting guidelines
- feature proposal flow
- pull request requirements
- code style and testing expectations
License
This project is licensed under the MIT LICENSE
Metadata
Release files for hexo 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hexo-0.2.1.tar.gz | 50.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hexo-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.9 kB
Release files / hexo-0.2.1.tar.gz
| Download URL | hexo-0.2.1.tar.gz |
|---|---|
| Size | 50.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c312516aa2b422834a9dbce5d8492e37e3c7e68bc10326a42c73e6c39dcd5e0
|
|
BLAKE2b-256 checksum How to use checksums |
ad69335f70e5873e8d661c0facbbb0bcb34592b5ce3f388ebff55d35569d06bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / hexo-0.2.1-py3-none-any.whl
| Download URL | hexo-0.2.1-py3-none-any.whl |
|---|---|
| Size | 11.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5393e915f830e224bd8c113112550ae2c645fff72c0b159936201a9ebdb6dbd2
|
|
BLAKE2b-256 checksum How to use checksums |
44dfe1f5314736168825e4230357083d457c28de574940210dde10699956938b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency log