A robust, modular, enterprise-level game engine for the strategic board game Zai (齋).
Zai is a two-player abstract strategy game played on a hexagonal grid where players must balance territorial expansion with network connectivity. The game features four win conditions and deep strategic complexity.
The engine is built with enterprise-level design principles:
- Immutable State: All game states are immutable for thread-safety
- Modular Design: Each system is independent and testable
- Performance Optimized: O(n) connectivity checks, alpha-beta pruning
- Type Safe: Comprehensive type hints throughout
- Zero Dependencies: Pure Python implementation
-
core/hex.py - Hexagonal coordinate system
- Axial coordinate representation
- Neighbor calculations
- Distance metrics
- Edge detection
-
core/entities/player.py - Player and stone entities
- Player enumeration (White, Red, Void)
- Stone data structure
- Game phase tracking
-
core/entities/move.py - Move representations
- Placement moves
- Sacrifice moves
- Move factories
-
core/connectivity.py - Network analysis
- BFS connectivity checking
- Articulation point detection (Tarjan's algorithm)
- Bridge detection
- Component analysis
-
core/win_detector.py - Win condition detection
- Isolation detection
- Territory control (void-adjacent hexes)
- Encirclement detection
- Network completion (all edges touched)
-
core/move_generator.py - Legal move generation
- Placement move generation
- Sacrifice move generation
- Connectivity-aware move filtering
-
core/game_state.py - State management
- Immutable game state
- State transitions
- Serialization/deserialization
- Zobrist hashing support
-
core/evaluator.py - Position evaluation
- Material evaluation
- Territorial control
- Network strength
- Edge progress
- Encirclement threats
-
core/ai_engine.py - AI player
- Minimax with alpha-beta pruning
- Iterative deepening
- Transposition tables
- Time-limited search
-
core/game_engine.py - Main game engine
- High-level game API
- Game mode management
- Move validation
- AI integration
Install via pip:
pip install zai_engineOr with uv (recommended):
uv add zai_engineFor development, clone the repository and install with dev dependencies:
git clone https://github.com/OVECJOE/zai.git
cd zai
uv sync --devfrom zai_engine.game_engine import GameEngine, GameMode
from zai_engine.entities.move import PlacementMove
from zai_engine.hex import Hex
# Create engine
engine = GameEngine(mode=GameMode.HUMAN_VS_HUMAN)
# Make moves
engine.make_move(PlacementMove(Hex(1, 0))) # White
engine.make_move(PlacementMove(Hex(-1, 0))) # Red
# Check game state
print(f"Current player: {engine.get_current_player()}")
print(f"Legal moves: {len(engine.get_legal_moves())}")from zai_engine.game_engine import GameEngine, GameMode, Difficulty
from zai_engine.entities.player import Player
from zai_engine.entities.move import PlacementMove
from zai_engine.hex import Hex
engine = GameEngine(mode=GameMode.HUMAN_VS_AI)
engine.configure_ai(Player.RED, Difficulty.MEDIUM)
# Human makes a move
engine.make_move(PlacementMove(Hex(1, 0)))
# AI responds
ai_move = engine.make_ai_move()
print(f"AI played: {ai_move}")from zai_engine.game_engine import GameEngine, GameMode, Difficulty
engine = GameEngine(mode=GameMode.AI_VS_AI)
engine.ai_difficulty = Difficulty.EASY
while not engine.is_game_over():
# Alternate AI player each turn
engine.ai_player = engine.get_current_player()
engine.make_ai_move()
print(f"Winner: {engine.get_winner()}")- 7×7 hexagonal board (61 hexes)
- Center hex contains neutral Void Stone
- Each player has 24 stones (White and Red)
Placement Phase (Turns 1-12)
- Place one stone per turn
- Must be adjacent to Void Stone OR your existing stones
Expansion Phase (Turn 13+)
- Place one stone, OR
- Sacrifice one stone to place two stones
Your stones must remain connected at all times. If your network becomes disconnected, you lose immediately.
- Encirclement: Completely surround opponent's stones
- Territory Dominance: Control 5+ of 6 void-adjacent hexes
- Network Completion: Create connected chain touching all 6 board edges
- Opponent Isolation: Force opponent to disconnect their network
new_game()- Start new gamemake_move(move)- Make a movemake_ai_move()- Let AI make a moveis_game_over()- Check if game endedget_winner()- Get winner
get_legal_moves()- All legal moves for current playeris_valid_move(move)- Validate a move
get_current_player()- Active playerget_current_state()- Current GameState objectget_winner()- Winner (if game is over)
configure_ai(player, difficulty)- Configure AI for a playermake_ai_move()- Let configured AI make a move
- EASY: Depth 2, 1.0s time limit
- MEDIUM: Depth 4, 2.0s time limit
- HARD: Depth 6, 5.0s time limit
- EXPERT: Depth 8, 10.0s time limit
- Move generation: O(n) where n = stone count
- Connectivity check: O(n)
- Win detection: O(n²) worst case
- AI search: O(b^d) where b = branching factor, d = depth
- Game state: O(n)
- Transposition table: O(1M) positions cached
- Move history: O(m) where m = total moves
- Move validation: <1ms
- Connectivity check: <1ms
- AI move (Medium): ~100-500ms
- AI move (Hard): ~2-5s
Run the comprehensive test suite:
pytest tests/The test suite includes:
test_hex.py- Hex coordinate system and grid operationstest_move.py- Move creation and validationtest_connectivity.py- Network connectivity analysistest_win_detector.py- Win condition detectiontest_move_generator.py- Legal move generationtest_game_state.py- State management and transitionstest_evaluator.py- Position evaluationtest_ai_engine.py- AI search and decision making
All game states are immutable using frozen=True dataclasses and frozenset/tuple collections. This enables:
- Thread-safe operations
- Easy state caching
- Reliable undo/redo (with history stack)
Multiple AI difficulty levels with different search parameters
Move creation through factory functions
Game state changes can be monitored through state exports
Extend WinDetector.check_winner():
def detect_custom_condition(self, stones, player):
# Your logic here
return winner if condition_met else NoneExtend PositionEvaluator.evaluate():
def _evaluate_custom_feature(self, state, player, opponent):
# Your heuristic
return scoreModify HexGrid initialization:
grid = HexGrid(radius=4) # 9×9 boardThis engine is production-ready with:
✅ Comprehensive error handling ✅ Type safety throughout ✅ Immutable state management ✅ Performance optimization ✅ Clean separation of concerns ✅ Extensive documentation ✅ Example usage and tests ✅ Zero external dependencies
Potential additions for integration:
- Persistent storage - Save/load games
- Network protocol - Multiplayer support
- Opening book - Pre-computed opening moves
- Neural network evaluation - ML-based position scoring
- Puzzle mode - Tactical training positions
- Replay analysis - Post-game review tools
This engine is provided as-is for educational and development purposes.
Game Design: Zai (齋) - "pure" or "abstain" Engine Implementation: Enterprise-level Python architecture AI: Minimax with alpha-beta pruning and iterative deepening