UHP Utils
Dependency-free Python tools for running, testing, and comparing Universal Hive Protocol (UHP) engines.
Installation
Python 3.9 or newer is required. From the repository root, run:
python3 -m pip install .
Use without installation
Run the provided files from the repository root. They accept the same options as the installed commands:
| Utility | Without installation |
|---|---|
uhp-wrapper |
python3 uhp_wrapper.py |
uhp-arena |
python3 arena.py |
uhp-compare-validmoves |
python3 compare_validmoves.py |
uhp-compare-perft |
python3 compare_perft.py |
uhp-to-pgn |
python3 uhp_to_pgn.py |
For example:
python3 arena.py ./engine-a ./engine-b
Quick example
Start one game between two engines:
uhp-arena ./engine-a ./engine-b
Every command provides its full option list through --help.
Contents
| Utility | Functionality |
|---|---|
| Use without installation | Run each utility from its provided Python file. |
| Engine inputs | Use native executables or local Docker images. |
uhp-wrapper |
Send UHP commands to one engine interactively. |
uhp-arena |
Play matches between two engines and save results. |
uhp-compare-validmoves |
Find legal-move differences across recorded positions. |
uhp-compare-perft |
Compare perft counts and isolate the first divergent branch. |
uhp-to-pgn |
Convert a UHP game string to readable PGN-style text. |
| Python API | Use the same utilities as a library. |
Engine inputs
Whenever a utility asks for an engine, provide one of these values:
- A local executable:
./engine - A command available on
PATH:hive-engine - A local Docker image:
example/hive-engine:latest
The utility first looks for an executable or command. If none is found, it
looks for a local Docker image with that name. Images are never pulled: the
image must already exist and its ENTRYPOINT must start the UHP engine.
Native engine flags use options such as --engine-arg, --white-arg, or
--engine-a-arg. Write a flag that begins with - using the equals form, for
example --engine-arg=--fast. Environment variables use --env KEY=value or
an engine-specific option such as --white-env KEY=value. Docker images accept
environment variables, but not native engine flags.
uhp-wrapper
Open a terminal connected to one engine:
uhp-wrapper ./engine
Type UHP commands at the UHP> prompt. The wrapper prints the complete engine
response. Use restart to restart the engine, terminate to stop it, and
quit or exit to close the wrapper.
To pass a native engine flag, set an environment variable, and limit how long each command may run:
uhp-wrapper ./engine --engine-arg=--fast --env THREADS=4 --timeout 10
Use --startup-timeout if engine startup needs a separate limit.
uhp-arena
Play one game between two engines:
uhp-arena ./engine-a ./engine-b
By default, each engine gets five seconds per move. Multiple games alternate
which engine plays White. Results are saved to logs/results.json with the
final state and complete move list.
To play 20 games using a fixed search depth and a 300-move draw limit:
uhp-arena ./engine-a ./engine-b --games 20 --depth 6 --max-moves 300
Choose either --depth N or --time SECONDS. The default game type is
Base+MLP. Use --results-file PATH to change the output file or
--no-results to disable it. Optional --command-timeout and
--search-timeout values set wall-clock limits.
uhp-compare-validmoves
Compare the legal moves reported by two engines:
uhp-compare-validmoves ./engine-a ./engine-b positions.uhp
positions.uhp must contain one UHP game string per line. By default, the
utility checks the position before the last move of each game and prints any
moves reported by only one engine. Blank lines and # comments are ignored.
To check every position in every game using four workers:
uhp-compare-validmoves ./engine-a ./engine-b positions.txt \
--full-game --workers 4
Use - instead of the file name to read stdin. Differences are also verified
by playing the other engine's moves; --no-cross-check skips this. Each worker
starts one copy of both engines.
uhp-compare-perft
Compare perft counts from the initial Base-game position through depth 2:
uhp-compare-perft ./engine-a ./engine-b 'Base;NotStarted;White[1]' 2
The arguments are the two engines, the UHP position, and the maximum depth. The utility compares every reported count and, when they differ, follows the tree to find the first divergent position.
To test a position from a game through depth 4 with a 30-second command limit:
uhp-compare-perft ./engine-a ./engine-b \
'Base+MLP;InProgress;White[2];wA1;bA1 -wA1' 4 --timeout 30
Expected perft command
Both engines must accept this line-oriented command after the position has
been loaded with newgame:
perft N
N is a positive integer. For every depth from 1 through N, the engine
must return the number of leaf nodes reachable in exactly that many plies from
the current position. A depth 0 row with count 1 is optional. The response
must finish with ok on its own line.
The preferred response format is:
perft 3
1: 37
2: 1,369
3: 65,631
ok
The first line above is the command sent to the engine; the remaining lines
are its response. Counts must be decimal integers and may contain comma
separators. DEPTH COUNT is also accepted. Engines may instead return a table:
depth count time
1 37 5us
2 1369 112us
3 65631 2ms
ok
In table output, the first two columns must be the numeric depth and count. A
header and extra columns are ignored. Missing depths, non-numeric counts, or a
missing ok terminator are invalid responses.
If counts differ, the utility uses validmoves, play or pass, and undo 1
to locate the first divergent branch, so both engines must support those UHP
commands too. Use --valid-moves-only to skip perft and compare only the
legal moves at the supplied position.
uhp-to-pgn
Convert a UHP game string and print the PGN-style result:
uhp-to-pgn 'Base;WhiteWins;Black[1];wA1'
The output contains game metadata followed by the numbered moves. It is printed to the terminal by default.
To add player names and save the result to a file:
uhp-to-pgn 'Base;WhiteWins;Black[1];wA1' \
--white Alice --black Bob --output game.pgn
Input may also come from --input FILE or stdin. Use --site, --date, and
repeatable --tag KEY=value options for additional metadata.
Python API
from uhp_utils import EngineWrapper
with EngineWrapper("./engine") as engine:
moves = engine.command("validmoves")
EngineWrapper starts the engine, sends complete UHP commands, and closes the
process automatically. The package also exports Arena, UHPState,
compare_valid_moves, compare_perft, convert_uhp_to_pgn, structured result
types, Docker helpers, and engine error classes.
License
MIT
With love @dortojekyll
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uhp_utils-0.1.0.tar.gz.
File metadata
- Download URL: uhp_utils-0.1.0.tar.gz
- Upload date:
- Size: 133.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a7df115261daa4feea97fb8543b73d031722cd48ad7d5eda446e0a3cd735c82
|
|
| MD5 |
bf94b9c11e7a5ac7f51b960b1fd74091
|
|
| BLAKE2b-256 |
544423d678fec60d2a3a14cf22ee0f8fea5954f914d2fc1a05b2ccee7476b081
|
File details
Details for the file uhp_utils-0.1.0-py3-none-any.whl.
File metadata
- Download URL: uhp_utils-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c13d08e62bbf8b7dea130a24865d924270357cc2d8dc784ed5b61908edee853a
|
|
| MD5 |
1e48feb4d94ad792a74f482370faab19
|
|
| BLAKE2b-256 |
27f245bc07a7a66242005cf3910a179e61a92ed1b9ddc5d5aeed5f85147ffa37
|