三人麻雀(萬子なし・北なし)の牌効率を学ぶためのプロジェクトです。計算部分は外部依存なしのPythonライブラリ sanma として切り出してあり、それを使うWebアプリ(FastAPI + React)が同梱されています。
| ディレクトリ | 内容 |
|---|---|
sanma/ |
牌効率計算ライブラリ。シャンテン数・受け入れ枚数・打牌評価。外部依存なし |
backend/ |
FastAPIのゲームAPI。sanma を呼ぶだけの薄い層 |
frontend/ |
React UI |
tests/ |
60件のテスト |
pip install sanmaimport sanma
hand = sanma.parse("123456789p123s5s")
sanma.shanten(hand) # 0(和了形は -1)
sanma.ukeire(hand) # {'5s': 3} シャンテンを進める牌と残り枚数
sanma.best_discard(sanma.parse("123456789p123s5s7z")) # '7z'詳しくは sanma/README.md を参照してください。
三人麻雀は萬子と北を使わないため、牌種は24種・96枚です(4人麻雀は34種・136枚)。ここから2つの違いが出ます。
受け入れ枚数は山の構成に依存するので、4人麻雀向けの数字はそのまま使えません。また么九牌が10種しかないため、13種必要な国士無双は成立しません。
一方でシャンテン数そのものは、どちらの麻雀でも手牌だけで決まる同じ関数です。このライブラリは MahjongRepository/mahjong(天鳳の牌譜2,600万手で検証されている)との差分テストで検証しています。国士を無効にした条件で、ランダム手牌8,000件に対し不一致0件でした。
つまり、既存ライブラリで足りない部分は受け入れ計算と打牌評価であり、そこがこのライブラリの担当範囲です。
Python 3.13 / M1 Mac での計測です。
| 項目 | 値 |
|---|---|
| テスト | 60件パス |
| 既存ライブラリとの差分照合 | 8,000手牌で不一致0件(国士無効時) |
| 分析APIのレイテンシ | 中央値 2.9ms / p95 24.9ms |
| 100局の自動プレイ | エラー0件・和了35局・流局65局(うちテンパイ36局) |
シャンテン計算は筒子・索子・字牌をスート単位で分解してメモ化しています。手牌全体をキーにするよりキャッシュ命中率が高く、同一局面を繰り返し評価する受け入れ計算で効きます。
# バックエンド
cd backend
pip install -r requirements.txt
uvicorn server:app --reload --port 8001
# フロントエンド(別ターミナル)
cd frontend
yarn install
yarn startフロントエンドは http://localhost:3000 、APIは http://localhost:8001 で起動します。詳細は SETUP_GUIDE.md を参照してください。
pip install pytest mahjong
python -m pytest tests/ -vmahjong は差分テスト専用の依存です。入っていない場合、差分テストだけスキップされます。ライブラリ本体は外部依存なしで動きます。
| メソッド | パス | 内容 |
|---|---|---|
| GET | /api/health |
ヘルスチェック |
| POST | /api/game/start |
新規対局を開始(自分は14枚配牌) |
| GET | /api/game/{game_id}/state |
対局状態を取得 |
| POST | /api/game/{game_id}/analyze |
手牌を分析 |
| POST | /api/game/{game_id}/discard |
打牌する |
| GET | /api/learning/tips |
学習用のヒントを取得 |
山が尽きると phase が finished になり、以降の打牌は 400 を返します。
分析レスポンスの例:
{
"shanten": 3,
"recommended_discard": "2z",
"efficiency_tiles": {"1p": 4, "4p": 4, "3s": 4},
"tile_analysis": {
"2z": {"shanten_after": 3, "ukeire_count": 43, "efficiency": 0.921, "safety": 0.85, "score": 0.899}
}
}実装済み: シャンテン計算(通常手・七対子)、受け入れ枚数、打牌評価、筋による安全度。
未実装: 鳴き(ポン・カン)、役と点数の計算、フリテン判定。安全度は牌の危険度を学ぶための目安であり、放銃率の推定ではありません。
MIT License