Competitive Mahjong AI engine supporting both Japanese Riichi (4-player) and MCR (Chinese Official) rules, with rule-specific strategy profiles designed for high-level play.
- Japanese Riichi Mahjong: Full yaku detection (30+ yaku including all yakuman), han/fu scoring, furiten tracking, riichi declaration
- MCR (Chinese Official): 81 fan pattern detection with exclusion rules, minimum 8-fan validation
- Riichi Strategy (Defensive): Tile efficiency optimization, push/fold EV framework, suji/kabe safety analysis, conservative calling policy, riichi timing
- MCR Strategy (Aggressive): Fan-targeting hand building, liberal calling policy, fan preservation scoring
- Shanten Calculator: Recursive suit decomposition with caching for fast tiles-to-tenpai calculation
- Tile Efficiency (Ukeire): Acceptance width calculation for optimal discard selection
- Defense Module: Suji inference, kabe (wall) analysis, composite danger evaluation, EV-based push/fold decisions
- Monte Carlo Simulation: Hidden tile sampling for probability estimation
- Game Engine: Complete game loop with draw, discard, chi/pon/kan, riichi, tsumo/ron
- Arena: Agent-vs-agent evaluation framework
pip install -e ".[dev]"from mahjong_ai.ai.agent import MahjongAgent
from mahjong_ai.rules.riichi import RiichiRuleSet
from mahjong_ai.training.arena import Arena
# Create 4 AI agents
players = [MahjongAgent.riichi() for _ in range(4)]
# Run a match
arena = Arena(RiichiRuleSet(), players)
stats = arena.run_match(num_rounds=8, num_games=100)
print(stats.summary())from mahjong_ai.core.tiles import TileSet
from mahjong_ai.shanten import shanten, ukeire
hand = TileSet.from_string("123m456p789s12z")
print(f"Shanten: {shanten(hand)}")
count, accepting = ukeire(hand)
print(f"Acceptance: {count} tiles, kinds: {accepting}")from mahjong_ai.core.hand import Hand, WinContext, WinType
from mahjong_ai.rules.riichi.scoring import calculate_score
hand = Hand.from_string("123m456p789s11177z")
ctx = WinContext(win_tile=33, win_type=WinType.RON, is_riichi=True)
score = calculate_score(hand, ctx)
print(f"{score.han} han / {score.fu} fu = {score.total_points} points")
print(f"Yaku: {score.yaku}")mahjong_ai/
├── core/ # Tile representation (34-array), melds, hands, wall, game state
├── shanten/ # Shanten calculator + tile efficiency (ukeire)
├── rules/
│ ├── riichi/ # Yaku detection, han/fu scoring, furiten tracking
│ └── mcr/ # 81 fan patterns, exclusion rules, MCR scoring
├── engine/ # Game loop, actions, player interface
├── defense/ # Suji, kabe, danger evaluation, push/fold framework
├── ai/ # Strategy agents, hand evaluator, Monte Carlo simulation
└── training/ # Arena for agent evaluation
Numbered suits: 123m (man/characters), 456p (pin/circles), 789s (sou/bamboo)
Honors (z): 1=East, 2=South, 3=West, 4=North, 5=White, 6=Green, 7=Red
pytest tests/ -v- Cython-accelerated shanten for 100x speedup
- Neural network policy via self-play reinforcement learning
- Opponent modeling from discard pattern analysis
- Tenhou/Majsoul replay import for supervised pre-training
- MCR knitted pattern support in shanten calculator
- Web interface for human vs AI play
MIT