Skip to main content

High-performance core utilities for Quantik game state manipulation

Project description

Quantik Core

codecov

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

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}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quantik_core-1.1.0.tar.gz (171.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quantik_core-1.1.0-py3-none-any.whl (95.4 kB view details)

Uploaded Python 3

File details

Details for the file quantik_core-1.1.0.tar.gz.

File metadata

  • Download URL: quantik_core-1.1.0.tar.gz
  • Upload date:
  • Size: 171.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for quantik_core-1.1.0.tar.gz
Algorithm Hash digest
SHA256 936181b1d161b379d364eb11455f9414b830a1e98591cdf4a0dc616ca36c64e3
MD5 d68355347aabd2051725f4c3b71753a0
BLAKE2b-256 3ddb4a515c971ad43dcb5c30cea0713d20af8016b9d4d6613f8a4827d62d781d

See more details on using hashes here.

File details

Details for the file quantik_core-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: quantik_core-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 95.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for quantik_core-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c7b93871f1ed636b24613c152d139374bc0d821622e1048be15c7c13eea53429
MD5 c4e509c860a5cf1ba6f8c7180f66f7de
BLAKE2b-256 c2aa7b8cb414c86fba49039cd78a915d93871e5b3e3cebc1469a3562490402b9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page