queens-generator
Generator and human-style solver for LinkedIn-Queens / Star Battle puzzles.
The package is named speed_stars (the original internal name) for backward compatibility with existing consumers; the project distribution is named queens-generator to match the player-facing brand.
This logic creates puzzles for Pemdas and validates community-submitted puzzles on Queens Puzzle Maker.
The generator refuses to ship any puzzle it can't solve without backtracking, using a hand-coded set of human deduction rules. When deduction stalls, instead of regenerating, it mutates the zone boundaries of the existing puzzle until deduction succeeds.
For the long-form write-up — why uniqueness isn't enough, how the deduction rules are ordered, why the generator refines instead of regenerates — see DESIGN.md.
Install
pip install queens-generator
# or, from a checkout:
pip install -e .
Usage
from speed_stars import generate_speed_stars_puzzle
puzzle = generate_speed_stars_puzzle(grid_size=6)
puzzle.zone_grid is a list-of-lists where each integer is a region ID:
[[1, 5, 5, 5, 5, 5],
[1, 1, 5, 5, 5, 5],
[4, 4, 4, 5, 2, 5],
[5, 5, 5, 5, 2, 3],
[5, 5, 0, 5, 2, 3],
[5, 0, 0, 3, 3, 3]]
puzzle.star_positions is the unique solution — one star per row, column, and region:
[Position(x=0, y=0), Position(x=1, y=3), Position(x=2, y=1),
Position(x=3, y=4), Position(x=4, y=2), Position(x=5, y=5)]
puzzle.deductions is the ordered sequence of human-style steps that solve the puzzle, each with a natural-language reason. The first few for the puzzle above:
Deduction(cells=[Position(2,3), Position(2,4), Position(2,5)],
state='crossedOut',
reason='row 3 can only have a star in {zone_4}')
Deduction(cells=[Position(0,4), Position(1,4), Position(5,4)],
state='crossedOut',
reason='column 5 can only have a star in {zone_2}')
Deduction(cells=[...8 cells...],
state='crossedOut',
reason='{zone_1}, {zone_5} must have stars in rows 1, 2')
The deduction list is also what powers in-app hints: each Deduction is explainable to a player without revealing the solution.
Difficulty
The generator discards puzzles that are too trivial. The thresholds are profiled per grid size in speed_stars/generate.py:
| grid size | min solve rounds | min cell deductions |
|---|---|---|
| 5 | 3 | 12 |
| 6 | 3 | 14 |
| 7 | 3 | 17 |
| 8 | 3 | 18 |
| 9 | 3 | 12 |
| 10–12 | 4 | 15 |
The thresholds count work done by the propagation solver (solve_speed_stars), which is what the generator uses to decide whether a puzzle is uniquely solvable without backtracking. The explainable Deduction list returned to the player is built by a separate pass (generate_deductions) that shares the same rules but reorders them by how easy they are for a human to spot.
- Rounds is how many passes the propagation solver makes through the grid before it stops finding new deductions. Each pass applies subset elimination then per-cell checks; below the threshold the puzzle falls open in a sweep or two and isn't interesting.
- Cell deductions counts the per-cell branches specifically — subset-elimination steps (N rows spanning N zones) are tracked separately and don't count, since they're easier for humans to spot. The threshold forces each puzzle to also demand the harder per-cell reasoning.
- Zone size: independent of grid size, every zone must have at least 3 cells (
MIN_ZONE_SIZE). Smaller zones produce one-step "only cell left" deductions that aren't interesting.
A puzzle that solves but fails any threshold is discarded; generation retries from scratch with a fresh zone layout. Zone-boundary refinement only runs to make unsolvable puzzles solvable, never to make easy puzzles harder.
The thresholds are exposed and overridable:
from speed_stars import generate_speed_stars_puzzle, RECOMMENDED_THRESHOLDS
# Use the profiled defaults
puzzle = generate_speed_stars_puzzle(grid_size=8)
# Override for a specific run (e.g., easier 8x8 for a tutorial pack)
puzzle = generate_speed_stars_puzzle(grid_size=8, min_rounds=2, min_deductions=10)
Grid sizes outside the profiled range fall back to the nearest known size via get_default_thresholds.
Tests
pip install -e .[dev]
python -m pytest tests/
License
MIT.
Metadata
Release files for queens-generator 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| queens_generator-0.1.0.tar.gz | 22.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| queens_generator-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.6 kB
Release files / queens_generator-0.1.0.tar.gz
| Download URL | queens_generator-0.1.0.tar.gz |
|---|---|
| Size | 22.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
56bd415b0824afa6f8b7697c2b2a1c7d010891ebd61670fc646473435e060d3a
|
|
BLAKE2b-256 checksum How to use checksums |
2428b0da9be6e94a417a352bd818851cddc0aafd3ad9bcf8c00b4b1d577b3291
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.2
|
Release files / queens_generator-0.1.0-py3-none-any.whl
| Download URL | queens_generator-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d87540e60a154e6bf23103f08dd4f02ee67fada65e1b96ad7d4de057c1c6a8fd
|
|
BLAKE2b-256 checksum How to use checksums |
520e0483c0e8379cec78d57e2ed2c17095e2dd2a21898adf61169a530487a6e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.2
|