Quantik Core
A high-performance Python library for manipulating Quantik game states, optimized for Monte Carlo simulations, game analysis, and AI engines.
What is Quantik?
Quantik is an elegant 4×4 abstract strategy game where players compete to complete lines with all four unique shapes.
Game Rules
- Board: 4×4 grid (16 squares)
- Pieces: 4 different shapes (A, B, C, D) in 2 colors (one per player)
- Objective: Be the first to complete a row, column, or 2×2 zone containing all four different shapes
- Gameplay:
- Players alternate placing one of their remaining pieces on an empty square
- A piece cannot be placed if the opponent already has the same shape in the target square's row, column, or 2×2 zone
- Colors don't matter for winning - only the presence of all four shapes in a line
Example Victory
A b C d ← Row with all 4 shapes = WIN!
. . . .
. . . .
. . . .
QFEN Notation
Board states are represented using QFEN (Quantik FEN) notation - a human-readable format inspired by chess FEN.
Format Structure
QFEN uses 4 slash-separated ranks representing rows from top to bottom:
rank1/rank2/rank3/rank4
4×4 Grid Layout
┌─────┬─────┬─────┬─────┐
│ 0 │ 1 │ 2 │ 3 │ ← Rank 1: positions 0-3
├─────┼─────┼─────┼─────┤
│ 4 │ 5 │ 6 │ 7 │ ← Rank 2: positions 4-7
├─────┼─────┼─────┼─────┤
│ 8 │ 9 │ 10 │ 11 │ ← Rank 3: positions 8-11
├─────┼─────┼─────┼─────┤
│ 12 │ 13 │ 14 │ 15 │ ← Rank 4: positions 12-15
└─────┴─────┴─────┴─────┘
Notation Rules
- A, B, C, D = Player 0 pieces (uppercase) with shapes A, B, C, D
- a, b, c, d = Player 1 pieces (lowercase) with shapes A, B, C, D
- . = Empty square
- / = Rank separator
Visual Examples
1. Empty Board
QFEN: "..../..../..../...."
┌─────┬─────┬─────┬─────┐
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
└─────┴─────┴─────┴─────┘
2. Mixed Position
QFEN: "A.bC/..../d..B/...a"
┌─────┬─────┬─────┬─────┐
│ A │ . │ b │ C │ ← Player 0: A,C Player 1: b
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ d │ . │ . │ B │ ← Player 0: B Player 1: d
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ a │ ← Player 1: a
└─────┴─────┴─────┴─────┘
3. Winning Position (Complete Row)
QFEN: "AbCd/..../..../...."
┌─────┬─────┬─────┬─────┐
│ A │ b │ C │ d │ ← WIN! All 4 shapes in top row
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
├─────┼─────┼─────┼─────┤
│ . │ . │ . │ . │
└─────┴─────┴─────┴─────┘
4. Complex Game State
QFEN: "Ab.C/d.BA/.cb./D.a."
┌─────┬─────┬─────┬─────┐
│ A │ b │ . │ C │ ← Player 0: A,C Player 1: b
├─────┼─────┼─────┼─────┤
│ d │ . │ B │ A │ ← Player 0: B,A Player 1: d
├─────┼─────┼─────┼─────┤
│ . │ c │ b │ . │ ← Player 1: c,b
├─────┼─────┼─────┼─────┤
│ D │ . │ a │ . │ ← Player 0: D Player 1: a
└─────┴─────┴─────┴─────┘
Features
This library provides the core foundation for building:
- Monte Carlo Tree Search (MCTS) engines
- Parametrizable beam search for memory-bounded terminal-state discovery
- Game analysis and position evaluation systems
- AI training and recommendation engines
- Opening book generation and endgame databases
- Statistical analysis of game patterns
- Game engines and tournament systems
- Research tools for combinatorial game theory
Current Implementation:
- State Representation: Complete bitboard-based game state management
- Move Generation: Full legal move generation with placement validation
- Game Logic: Win detection, move validation, and game result checking
- MCTS Engine: Monte Carlo Tree Search with UCB1 selection
- Beam Search Engine: memory-bounded frontier search guaranteeing true terminal states
- Opening Book: SQLite-backed position database with canonical deduplication
- Puzzle Generator: Tactical puzzle generation with dropout-based search
- Serialization: Binary, QFEN, and CBOR formats
- Canonicalization: Symmetry-aware position normalization
Core Capabilities
- Blazing Fast Operations: Bitboard-based representation enables O(1) move generation and win detection
- Compact Memory Footprint: Game states fit in just 16 bytes with optional 18-byte canonical serialization
- Symmetry Normalization: Automatic canonicalization under rotations, reflections, color swaps, and shape relabeling
- Cross-Language Compatibility: Binary format designed for interoperability with Go, Rust, and other engines
- Human-Readable Format: QFEN (Quantik FEN) notation for debugging and documentation
- Self-Describing Serialization: CBOR-based format for robust data exchange
Installation
pip install quantik-core
Quick Start
Basic State Manipulation
from quantik_core import State, Move, generate_legal_moves, apply_move
# Create an empty game state
state = State.empty()
print(state.to_qfen()) # Output: ..../..../..../....
# Create positions using QFEN notation (see QFEN section for visual examples)
state = State.from_qfen("A.bC/..../d.B./...a") # Mixed position
state = State.from_qfen("ABCD/..../..../....") # Player 0 wins with top row
# Convert to human-readable format
qfen = state.to_qfen()
print(f"Position: {qfen}") # Output: ABCD/..../..../....
# Get canonical representation for symmetry analysis
canonical_key = state.canonical_key()
print(f"Canonical key: {canonical_key.hex()}")
# Serialize to binary format (18 bytes)
binary_data = state.pack()
restored_state = State.unpack(binary_data)
# Serialize to CBOR for cross-language compatibility
cbor_data = state.to_cbor(canon=True, meta={"game_id": 123})
restored_from_cbor = State.from_cbor(cbor_data)
Monte Carlo Tree Search
from quantik_core import State
from quantik_core.mcts import MCTSEngine, MCTSConfig
# Configure MCTS search
config = MCTSConfig(
max_iterations=1000,
exploration_weight=1.414, # sqrt(2) for UCB1
random_seed=42
)
# Create engine and search
engine = MCTSEngine(config)
state = State.from_qfen("..../..../..../....")
# Find best move
move, win_probability = engine.search(state)
print(f"Best move: {move}, Win probability: {win_probability:.2%}")
Beam Search
from quantik_core import State
from quantik_core.beam_search import BeamSearchEngine, BeamSearchConfig
# Configure beam search (guarantees reaching true terminal states).
# beam_width can also be a depth-dependent beam_schedule=[...] — see
# docs/BEAM_SEARCH.md's Tuning section for an exhaustive-prefix recipe.
config = BeamSearchConfig(
beam_width=8,
max_depth=16,
random_seed=42
)
# Create engine and search
engine = BeamSearchEngine(config)
state = State.from_qfen("..../..../..../....")
# Find the best line for the root player
result = engine.search(state)
print(f"Reached terminal: {result.reached_terminal}")
print(f"Best line: {result.best_leaf.moves}")
# Rank multiple root move options (beam-sampled, not proven minimax)
for entry in result.ranked_root_moves(top_k=3):
print(f"{entry.move}: win_probability={entry.win_probability:.2%}")
Opening Book Database
from quantik_core import State, Move
from quantik_core.opening_book import OpeningBookDatabase, OpeningBookConfig
# Create opening book
config = OpeningBookConfig(database_path="quantik_openings.db")
db = OpeningBookDatabase(config)
# Add positions
state = State.from_qfen("A.../..../..../....")
db.add_position(
state=state,
evaluation=0.5,
visit_count=100,
win_count_p0=60,
win_count_p1=40,
draw_count=0,
best_moves=[Move(player=0, shape=1, position=5)],
depth=1
)
# Query positions
entry = db.get_position(state)
if entry:
print(f"Evaluation: {entry.evaluation}")
print(f"Best moves: {entry.best_moves}")
Performance
- State Operations: Bitboard-based representation enables fast position manipulation
- Canonicalization: <1µs per position with precomputed lookup tables
- Memory Usage: 16 bytes per game state + 1MB for transformation LUTs
- Serialization: 18-byte binary format, human-readable QFEN, or self-describing CBOR
- MCTS: ~150-210 iterations/second from the empty board (pure-Python UCT; dominated by per-iteration playout cost, not tree overhead)
- Puzzle Generation: 55,000+ positions/second with dropout optimization
- Opening Book: SQLite backend with canonical deduplication for space efficiency
Use Cases
Position Analysis and Canonicalization
from quantik_core import State
# Create different equivalent positions
pos1 = State.from_qfen("A.../..../..../....")
pos2 = State.from_qfen("..../..../..../.B..") # Rotated + shape equivalence
# Both have the same canonical representation
assert pos1.canonical_key() == pos2.canonical_key()
Database Storage and Retrieval
# Use canonical keys as database indices
positions_db = {}
canonical_key = state.canonical_key()
positions_db[canonical_key] = {"eval": 0.75, "visits": 1000}
Cross-Language Data Exchange
# Save position with metadata for other engines
data = state.to_cbor(
canon=True,
mc=5000, # Monte Carlo simulations
meta={"depth": 12, "engine": "quantik-py-v1"}
)
# Binary format for high-performance applications
binary = state.pack() # Just 18 bytes
Documentation
- Minimax Documentation - Alpha-beta search with a fitted handcrafted evaluation
- MCTS Documentation - Monte Carlo Tree Search implementation details
- Beam Search Documentation - Memory-bounded terminal-state search
- Search Telemetry - Event counters, value semantics, and root-identity rules shared by MCTS, beam, and minimax
- Opening Book Guide - Position database usage and API
- Examples - Complete working examples for all features
Technical Details
- Representation: 8 disjoint 16-bit bitboards (one per color-shape combination)
- Symmetries: Dihedral group D4 (8 rotations/reflections) × color swap × shape permutations = 384 total
- Serialization: Versioned binary format with little-endian 16-bit words
- Canonicalization: Lexicographically minimal representation across symmetry orbit
- MCTS Algorithm: UCB1 with configurable exploration parameter
- Opening Book: Canonical key indexing for automatic deduplication
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
License
MIT License - see LICENSE for details.
Citation
If you use this library in research, please cite:
@software{quantik_core,
title={Quantik Core: High-Performance Game State Manipulation},
author={Mauro Berlanda},
year={2025},
url={https://github.com/mberlanda/quantik-core-py}
}
Metadata
Release files for quantik-core 1.3.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 | Provenance | |
|---|---|---|---|---|
| quantik_core-1.3.0.tar.gz | 200.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quantik_core-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 313.7 kB
Release files / quantik_core-1.3.0.tar.gz
| Download URL | quantik_core-1.3.0.tar.gz |
|---|---|
| Size | 200.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e53232ec013470c7682bfdbc585a2dc970e6b335b00f0a688756138fea3ce435
|
|
BLAKE2b-256 checksum How to use checksums |
7565cdf336b86d35f9fd4da3fde259a929f01d1cdf4549375055cda2c36575ad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / quantik_core-1.3.0-py3-none-any.whl
| Download URL | quantik_core-1.3.0-py3-none-any.whl |
|---|---|
| Size | 113.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
54455b0158c039fe224e39a29aeb5b026626618f0c1edc0a5d630b6b69ca9e5c
|
|
BLAKE2b-256 checksum How to use checksums |
d775864f0ef60b061918468d5b5da63708382d32adc6c18b3d76b2a89bec43e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for quantik-core 1.3.0
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.