riichi_engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +19 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- data/.github/pull_request_template.md +15 -0
- data/.github/workflows/ci.yml +22 -0
- data/.github/workflows/release.yml +31 -0
- data/.gitignore +6 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +164 -0
- data/docs/adapter_contract.md +144 -0
- data/docs/api_reference.md +309 -0
- data/docs/concepts.md +134 -0
- data/docs/public_api_policy.md +94 -0
- data/docs/state_machine.md +360 -0
- data/docs/usage_examples.md +265 -0
- data/lib/mahjong/config/rule_config.rb +53 -0
- data/lib/mahjong/cpu/ai/base_ai.rb +50 -0
- data/lib/mahjong/cpu/ai/easy_ai.rb +11 -0
- data/lib/mahjong/cpu/ai/hard_ai.rb +11 -0
- data/lib/mahjong/cpu/ai/normal_ai.rb +11 -0
- data/lib/mahjong/cpu/analysis/shanten.rb +112 -0
- data/lib/mahjong/cpu/analysis/tile_evaluator.rb +54 -0
- data/lib/mahjong/cpu/judges/naki_judge.rb +60 -0
- data/lib/mahjong/cpu/judges/riichi_judge.rb +42 -0
- data/lib/mahjong/cpu/selectors/dahai_selector.rb +97 -0
- data/lib/mahjong/errors/engine_error.rb +5 -0
- data/lib/mahjong/errors/invalid_action_error.rb +5 -0
- data/lib/mahjong/errors/invalid_state_error.rb +5 -0
- data/lib/mahjong/errors/tile_not_found_error.rb +5 -0
- data/lib/mahjong/flow/detectors/naki_detector.rb +82 -0
- data/lib/mahjong/flow/games/game_flow.rb +186 -0
- data/lib/mahjong/flow/resolvers/action_resolver.rb +22 -0
- data/lib/mahjong/flow/rounds/round_flow.rb +588 -0
- data/lib/mahjong/flow/validators/action_validator.rb +110 -0
- data/lib/mahjong/results/final_result.rb +11 -0
- data/lib/mahjong/results/game_flow_result.rb +20 -0
- data/lib/mahjong/results/game_result.rb +26 -0
- data/lib/mahjong/results/round_end_info.rb +18 -0
- data/lib/mahjong/results/round_flow_result.rb +18 -0
- data/lib/mahjong/scoring/calculators/fu_calculator.rb +68 -0
- data/lib/mahjong/scoring/calculators/score_calculator.rb +73 -0
- data/lib/mahjong/scoring/evaluators/win_evaluator.rb +111 -0
- data/lib/mahjong/scoring/judges/agari_judge.rb +68 -0
- data/lib/mahjong/scoring/judges/furiten_judge.rb +34 -0
- data/lib/mahjong/scoring/judges/machi_judge.rb +78 -0
- data/lib/mahjong/scoring/judges/yaku_judge.rb +161 -0
- data/lib/mahjong/scoring/parsers/hand_parser.rb +87 -0
- data/lib/mahjong/scoring/value_objects/score_result.rb +57 -0
- data/lib/mahjong/scoring/value_objects/yaku_context.rb +70 -0
- data/lib/mahjong/scoring/value_objects/yaku_entry.rb +7 -0
- data/lib/mahjong/scoring/value_objects/yaku_judge_result.rb +27 -0
- data/lib/mahjong/scoring/yaku/chankan.rb +6 -0
- data/lib/mahjong/scoring/yaku/chanta.rb +15 -0
- data/lib/mahjong/scoring/yaku/chiihou.rb +7 -0
- data/lib/mahjong/scoring/yaku/chiitoitsu.rb +6 -0
- data/lib/mahjong/scoring/yaku/chinitsu.rb +10 -0
- data/lib/mahjong/scoring/yaku/chinroutou.rb +6 -0
- data/lib/mahjong/scoring/yaku/chuuren_poutou.rb +20 -0
- data/lib/mahjong/scoring/yaku/daisangen.rb +8 -0
- data/lib/mahjong/scoring/yaku/daisuushii.rb +8 -0
- data/lib/mahjong/scoring/yaku/double_riichi.rb +6 -0
- data/lib/mahjong/scoring/yaku/haitei.rb +6 -0
- data/lib/mahjong/scoring/yaku/honitsu.rb +11 -0
- data/lib/mahjong/scoring/yaku/honroutou.rb +9 -0
- data/lib/mahjong/scoring/yaku/houtei.rb +6 -0
- data/lib/mahjong/scoring/yaku/iipeiko.rb +16 -0
- data/lib/mahjong/scoring/yaku/ikkitsuukan.rb +15 -0
- data/lib/mahjong/scoring/yaku/ippatsu.rb +6 -0
- data/lib/mahjong/scoring/yaku/junchan.rb +15 -0
- data/lib/mahjong/scoring/yaku/kokushi_musou.rb +6 -0
- data/lib/mahjong/scoring/yaku/menzen_tsumo.rb +6 -0
- data/lib/mahjong/scoring/yaku/pinfu.rb +16 -0
- data/lib/mahjong/scoring/yaku/riichi.rb +6 -0
- data/lib/mahjong/scoring/yaku/rinshan_kaihou.rb +6 -0
- data/lib/mahjong/scoring/yaku/ryanpeiko.rb +11 -0
- data/lib/mahjong/scoring/yaku/ryuuiisou.rb +6 -0
- data/lib/mahjong/scoring/yaku/san_ankou.rb +15 -0
- data/lib/mahjong/scoring/yaku/san_kantsu.rb +6 -0
- data/lib/mahjong/scoring/yaku/sanshoku_doujun.rb +15 -0
- data/lib/mahjong/scoring/yaku/sanshoku_doukou.rb +14 -0
- data/lib/mahjong/scoring/yaku/shousangen.rb +14 -0
- data/lib/mahjong/scoring/yaku/shousuushii.rb +14 -0
- data/lib/mahjong/scoring/yaku/suuankou.rb +15 -0
- data/lib/mahjong/scoring/yaku/suukantsu.rb +6 -0
- data/lib/mahjong/scoring/yaku/tanyao.rb +7 -0
- data/lib/mahjong/scoring/yaku/tenhou.rb +7 -0
- data/lib/mahjong/scoring/yaku/toitoihou.rb +7 -0
- data/lib/mahjong/scoring/yaku/tsuuiisou.rb +6 -0
- data/lib/mahjong/scoring/yaku/yakuhai.rb +27 -0
- data/lib/mahjong/snapshots/final_result_snapshot.rb +8 -0
- data/lib/mahjong/snapshots/game_progress_snapshot.rb +12 -0
- data/lib/mahjong/snapshots/game_setup_snapshot.rb +12 -0
- data/lib/mahjong/snapshots/win_evaluation_snapshot.rb +11 -0
- data/lib/mahjong/state/fuuro.rb +45 -0
- data/lib/mahjong/state/hand.rb +64 -0
- data/lib/mahjong/state/kawa.rb +68 -0
- data/lib/mahjong/state/mentsu.rb +55 -0
- data/lib/mahjong/state/round_state.rb +193 -0
- data/lib/mahjong/tiles/dora.rb +19 -0
- data/lib/mahjong/tiles/tile.rb +168 -0
- data/lib/mahjong/tiles/tile_set.rb +51 -0
- data/lib/mahjong/tiles/wall.rb +47 -0
- data/lib/mahjong/tiles/wanpai.rb +79 -0
- data/lib/riichi_engine/api.rb +62 -0
- data/lib/riichi_engine/version.rb +3 -0
- data/lib/riichi_engine.rb +15 -0
- data/riichi_engine.gemspec +32 -0
- metadata +207 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# API リファレンス
|
|
2
|
+
|
|
3
|
+
`RiichiEngine::API` は host app や adapter 層から `riichi_engine` を呼ぶための公開入口です。
|
|
4
|
+
|
|
5
|
+
局進行・和了評価・点数計算はすべてこのモジュールを経由してください。
|
|
6
|
+
内部 namespace(`Mahjong::Flow::*` 等)を host app から直接呼ぶことは避けてください(詳細は [公開 API ポリシー](public_api_policy.md))。
|
|
7
|
+
|
|
8
|
+
牌記法や麻雀用語については [概念・用語集](concepts.md) を参照してください。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 共通の型
|
|
13
|
+
|
|
14
|
+
### RuleConfig
|
|
15
|
+
|
|
16
|
+
ゲームルールを保持するオブジェクトです。引数なしでデフォルトルールを使えます。
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
rule = Mahjong::Config::RuleConfig.new # デフォルト
|
|
20
|
+
rule = Mahjong::Config::RuleConfig.new("kuitan" => false) # 食い断なし
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### RuleConfig の設定項目
|
|
24
|
+
|
|
25
|
+
| キー | 型 | デフォルト | 説明 |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `game_type` | String | `"hanchan"` | `"hanchan"`(東南戦)または `"tonpuu"`(東風戦) |
|
|
28
|
+
| `initial_score` | Integer | `25000` | 開始点数 |
|
|
29
|
+
| `oka_origin` | Integer | `30000` | オカの基準点 |
|
|
30
|
+
| `uma` | Array | `[20000, 10000, -10000, -20000]` | ウマ(1位から順) |
|
|
31
|
+
| `aka_dora` | Hash | `{ "m" => 1, "p" => 1, "s" => 1 }` | スートごとの赤ドラ枚数 |
|
|
32
|
+
| `kuitan` | Boolean | `true` | 食い断あり |
|
|
33
|
+
| `atozuke` | Boolean | `true` | 後付けあり |
|
|
34
|
+
| `double_yakuman` | Boolean | `false` | ダブル役満あり |
|
|
35
|
+
| `kazoe_yakuman` | Boolean | `true` | 数え役満あり |
|
|
36
|
+
| `kiriage_mangan` | Boolean | `false` | 切り上げ満貫あり |
|
|
37
|
+
| `triple_ron_draw` | Boolean | `true` | 三家和で流局 |
|
|
38
|
+
| `double_ron` | Boolean | `true` | ダブロンあり |
|
|
39
|
+
| `tobi` | Boolean | `true` | トビあり(点数が0点以下でゲーム終了) |
|
|
40
|
+
| `nishi_iri` | Boolean | `false` | 西入あり |
|
|
41
|
+
| `nishi_iri_threshold` | Integer | `30000` | 西入の基準点 |
|
|
42
|
+
| `renpuu_jantou_fu` | Integer | `2` | 連風牌を雀頭にしたときの符 |
|
|
43
|
+
|
|
44
|
+
### Snapshots
|
|
45
|
+
|
|
46
|
+
局の状態を gem へ渡すための値オブジェクトです。ActiveRecord を含まない plain Ruby の構造体です。
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
Mahjong::Snapshots::GameSetupSnapshot # 局開始情報
|
|
50
|
+
Mahjong::Snapshots::GameProgressSnapshot # 局終了後の進行情報
|
|
51
|
+
Mahjong::Snapshots::FinalResultSnapshot # ゲーム終了時の最終情報
|
|
52
|
+
Mahjong::Snapshots::WinEvaluationSnapshot # 和了評価用の情報
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
各フィールドは [使用例](usage_examples.md) のコードを参照してください。
|
|
56
|
+
|
|
57
|
+
### RoundState
|
|
58
|
+
|
|
59
|
+
局の進行状態を保持するオブジェクトです。
|
|
60
|
+
`setup_round` が返し、`apply_round_action` に渡し続けることで局が進行します。
|
|
61
|
+
JSON へのシリアライズ・デシリアライズが可能なので、キャッシュに保存して復元することもできます。
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
Mahjong::State::RoundState
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## メソッド一覧
|
|
70
|
+
|
|
71
|
+
### `setup_round(game_snapshot:, rule:, seed: nil)`
|
|
72
|
+
|
|
73
|
+
局の初期状態を構築します。牌山を生成し、配牌を行い、`RoundState` を返します。
|
|
74
|
+
|
|
75
|
+
**引数:**
|
|
76
|
+
|
|
77
|
+
| 引数 | 型 | 説明 |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `game_snapshot` | `GameSetupSnapshot` | 局番・点棒・親座席などの初期情報 |
|
|
80
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
81
|
+
| `seed` | `String \| nil` | 牌山の乱数シード。同じ seed で再現可能。省略するとランダム |
|
|
82
|
+
|
|
83
|
+
**返り値:** `Mahjong::State::RoundState`
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### `apply_round_action(state:, action:, rule:)`
|
|
88
|
+
|
|
89
|
+
局中のアクションを `state` に適用し、結果を返します。
|
|
90
|
+
`state` は破壊的に更新されます。
|
|
91
|
+
|
|
92
|
+
**引数:**
|
|
93
|
+
|
|
94
|
+
| 引数 | 型 | 説明 |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `state` | `RoundState` | 現在の局状態 |
|
|
97
|
+
| `action` | `Hash` | 適用するアクション |
|
|
98
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
99
|
+
|
|
100
|
+
**`action` の形式:**
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
{ type: :tsumo }
|
|
104
|
+
{ type: :dahai, seat: 0, tile: "5m" }
|
|
105
|
+
{ type: :riichi, seat: 0, tile: "3z" }
|
|
106
|
+
{ type: :pon, seat: 1, tiles: %w[5m 5m] }
|
|
107
|
+
{ type: :chi, seat: 1, tiles: %w[4m 6m] }
|
|
108
|
+
{ type: :ankan, seat: 0, tile: "5m" }
|
|
109
|
+
{ type: :kakan, seat: 0, tile: "5m" }
|
|
110
|
+
{ type: :daiminkan, seat: 1 }
|
|
111
|
+
{ type: :tsumo_agari, seat: 0 }
|
|
112
|
+
{ type: :ron_agari, seat: 1 }
|
|
113
|
+
{ type: :skip, seat: 2 }
|
|
114
|
+
{ type: :kyuushu_kyuuhai, seat: 0 }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
アクション種別の詳細は [概念・用語集](concepts.md#アクション種別) を参照してください。
|
|
118
|
+
|
|
119
|
+
**返り値:** `Mahjong::Results::RoundFlowResult`
|
|
120
|
+
|
|
121
|
+
| フィールド | 説明 |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `state` | 更新後の `RoundState` |
|
|
124
|
+
| `events` | このアクションで発生したイベントの配列 |
|
|
125
|
+
| `round_end?` | 局が終了したか否か |
|
|
126
|
+
| `round_end_info` | 局終了情報(`RoundEndInfo`)。局中は `nil` |
|
|
127
|
+
|
|
128
|
+
**例外:**
|
|
129
|
+
|
|
130
|
+
| 例外 | 発生条件 |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `RiichiEngine::API::InvalidActionError` | 不正なアクション(存在しない打牌・権利のない鳴きなど) |
|
|
133
|
+
| `RiichiEngine::API::EngineError` | エンジン内部エラー |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### `available_round_actions(state:, seat:, rule:)`
|
|
138
|
+
|
|
139
|
+
指定した `seat` が現在選択できるアクションの一覧を返します。
|
|
140
|
+
`apply_round_action` に渡す `action` の候補を取得するために使います。
|
|
141
|
+
|
|
142
|
+
**返り値:** `Array<Hash>`
|
|
143
|
+
|
|
144
|
+
各要素は `{ type: :dahai, tile: "5m" }` のような Hash です。
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `resolve_pending_action(pending_actions)`
|
|
149
|
+
|
|
150
|
+
複数の seat が同時に鳴き・ロンを宣言した場合(鳴き競合)に、優先順位を解決して1つのアクションを選びます。
|
|
151
|
+
|
|
152
|
+
**引数:**
|
|
153
|
+
|
|
154
|
+
| 引数 | 型 | 説明 |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `pending_actions` | `Hash{Integer => Array<Hash>}` | seat番号 → アクション配列 のマップ |
|
|
157
|
+
|
|
158
|
+
**返り値:** `Hash | nil`
|
|
159
|
+
競合を解決したアクション。有効なアクションがない場合は `nil`。
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### `tenpai_seats(state)`
|
|
164
|
+
|
|
165
|
+
現在の `RoundState` からテンパイしている座席の一覧を返します。
|
|
166
|
+
流局時のノーテン罰符計算の前に使います。
|
|
167
|
+
|
|
168
|
+
**返り値:** `Array<Integer>`(例: `[0, 2]`)
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### `calculate_tenpai_payments(tenpai_seats)`
|
|
173
|
+
|
|
174
|
+
流局時のノーテン罰符の支払い点数を計算します。
|
|
175
|
+
テンパイ者が受け取り、ノーテン者が支払う形で返します。
|
|
176
|
+
|
|
177
|
+
**引数:**
|
|
178
|
+
|
|
179
|
+
| 引数 | 型 | 説明 |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `tenpai_seats` | `Array<Integer>` | テンパイしている座席番号の配列 |
|
|
182
|
+
|
|
183
|
+
**返り値:** `Hash{Integer => Integer}`
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
# 例: seat 0, 2 がテンパイの場合
|
|
187
|
+
# => { 0 => 1500, 1 => -1500, 2 => 1500, 3 => -1500 }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
正の値が受け取り、負の値が支払いです。
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### `judge_next_game_round(progress_snapshot:, round_end_info:, rule:)`
|
|
195
|
+
|
|
196
|
+
局終了後に次局へ進むかゲームを終了するかを判定します。
|
|
197
|
+
オーラス・飛び・ゲーム終了条件なども考慮されます。
|
|
198
|
+
|
|
199
|
+
**引数:**
|
|
200
|
+
|
|
201
|
+
| 引数 | 型 | 説明 |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `progress_snapshot` | `GameProgressSnapshot` | 局終了後の点棒・場況 |
|
|
204
|
+
| `round_end_info` | `RoundEndInfo` | 局終了の詳細情報 |
|
|
205
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
206
|
+
|
|
207
|
+
**返り値:** `Mahjong::Results::GameFlowResult`
|
|
208
|
+
|
|
209
|
+
`GameFlowResult` の主要フィールド:
|
|
210
|
+
|
|
211
|
+
| フィールド | 説明 |
|
|
212
|
+
|---|---|
|
|
213
|
+
| `next_round?` | 次局へ進む場合 `true` |
|
|
214
|
+
| `game_end?` | ゲームを終了する場合 `true` |
|
|
215
|
+
| `next_bakaze` | 次局の場風(進行する場合) |
|
|
216
|
+
| `next_kyoku` | 次局の局番号 |
|
|
217
|
+
| `next_honba` | 次局の本場数 |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### `calculate_ranked_results(scores:, rule:)`
|
|
222
|
+
|
|
223
|
+
点棒だけからウマ・オカを含む最終順位と持ち点を計算します。
|
|
224
|
+
プレイヤー情報(名前・ID 等)が不要な場合に使います。
|
|
225
|
+
|
|
226
|
+
**引数:**
|
|
227
|
+
|
|
228
|
+
| 引数 | 型 | 説明 |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| `scores` | `Hash{Integer => Integer}` | seat番号 → 点棒 のマップ |
|
|
231
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
232
|
+
|
|
233
|
+
**返り値:** `Array<Mahjong::Results::FinalResult>`
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### `calculate_final_results(final_result_snapshot:, rule:)`
|
|
238
|
+
|
|
239
|
+
プレイヤー情報(名前・ID)付きの最終結果を計算します。
|
|
240
|
+
UI 表示用に情報が必要な場合はこちらを使います。
|
|
241
|
+
|
|
242
|
+
**引数:**
|
|
243
|
+
|
|
244
|
+
| 引数 | 型 | 説明 |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| `final_result_snapshot` | `FinalResultSnapshot` | 点棒とプレイヤー情報を含むスナップショット |
|
|
247
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
248
|
+
|
|
249
|
+
**返り値:** `Array<Mahjong::Results::FinalResult>`
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### `evaluate_win(state:, seat:, agari_type:, agari_tile:, rule:, extra_flags:, snapshot:)`
|
|
254
|
+
|
|
255
|
+
和了評価を行い、役一覧・翻数・符・点数計算結果を返します。
|
|
256
|
+
|
|
257
|
+
**引数:**
|
|
258
|
+
|
|
259
|
+
| 引数 | 型 | 説明 |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `state` | `RoundState` | 現在の局状態 |
|
|
262
|
+
| `seat` | `Integer` | 和了者の座席番号 |
|
|
263
|
+
| `agari_type` | `:tsumo \| :ron` | ツモ和了かロン和了か |
|
|
264
|
+
| `agari_tile` | `Tile \| String` | 和了牌(例: `"5m"`) |
|
|
265
|
+
| `rule` | `RuleConfig` | ゲームルール |
|
|
266
|
+
| `extra_flags` | `Hash` | 追加フラグ(チャンカン・リンシャンなど。通常は `{}`) |
|
|
267
|
+
| `snapshot` | `WinEvaluationSnapshot` | 場風・自風などの情報 |
|
|
268
|
+
|
|
269
|
+
**返り値:** `[winner_info, score_result]`
|
|
270
|
+
|
|
271
|
+
| 要素 | 型 | 説明 |
|
|
272
|
+
|---|---|---|
|
|
273
|
+
| `winner_info` | `Hash` | 役名・翻数・符を含む情報 |
|
|
274
|
+
| `score_result` | `Mahjong::Scoring::ValueObjects::ScoreResult` | 点数・各プレイヤーへの支払い情報(`.payments` で取得) |
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
### `agari?(tiles_34)`
|
|
279
|
+
|
|
280
|
+
牌の配列が和了形かどうかを判定します。
|
|
281
|
+
34形式については [概念・用語集](concepts.md#34形式tiles_34) を参照してください。
|
|
282
|
+
|
|
283
|
+
**返り値:** `true | false`
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### `deserialize_round_state(json)`
|
|
288
|
+
|
|
289
|
+
JSON 文字列から `RoundState` を復元します。
|
|
290
|
+
Redis やメモリキャッシュに保存した state を復元するときに使います。
|
|
291
|
+
|
|
292
|
+
**引数:**
|
|
293
|
+
|
|
294
|
+
| 引数 | 型 | 説明 |
|
|
295
|
+
|---|---|---|
|
|
296
|
+
| `json` | `String` | `RoundState` をシリアライズした JSON 文字列 |
|
|
297
|
+
|
|
298
|
+
**返り値:** `Mahjong::State::RoundState`
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## エラー
|
|
303
|
+
|
|
304
|
+
```ruby
|
|
305
|
+
RiichiEngine::API::InvalidActionError # 不正なアクション
|
|
306
|
+
RiichiEngine::API::EngineError # エンジン内部エラー
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
adapter 層でこれらを rescue してください。内部エラー(`Mahjong::Errors::*`)を直接 rescue する必要はありません。
|
data/docs/concepts.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# 概念・用語集
|
|
2
|
+
|
|
3
|
+
`riichi_engine` で使われる牌記法・麻雀用語・座席番号・アクション種別を解説します。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 牌記法
|
|
8
|
+
|
|
9
|
+
牌は `"数字 + スート"` の2文字の文字列で表します。
|
|
10
|
+
|
|
11
|
+
### スート一覧
|
|
12
|
+
|
|
13
|
+
| 記号 | 種別 | 例 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `m` | 萬子(マンズ) | `"1m"` = 一萬、`"9m"` = 九萬 |
|
|
16
|
+
| `p` | 筒子(ピンズ) | `"1p"` = 一筒、`"9p"` = 九筒 |
|
|
17
|
+
| `s` | 索子(ソーズ) | `"1s"` = 一索、`"9s"` = 九索 |
|
|
18
|
+
| `z` | 字牌(ジハイ) | `"1z"`〜`"7z"` |
|
|
19
|
+
|
|
20
|
+
### 赤ドラ
|
|
21
|
+
|
|
22
|
+
数字を `0` にすると赤五(赤ドラ)を表します。
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
"0m" = 赤五萬
|
|
26
|
+
"0p" = 赤五筒
|
|
27
|
+
"0s" = 赤五索
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 字牌一覧
|
|
31
|
+
|
|
32
|
+
| 記法 | 牌 | 種別 |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `"1z"` | 東 | 風牌(東) |
|
|
35
|
+
| `"2z"` | 南 | 風牌(南) |
|
|
36
|
+
| `"3z"` | 西 | 風牌(西) |
|
|
37
|
+
| `"4z"` | 北 | 風牌(北) |
|
|
38
|
+
| `"5z"` | 白 | 三元牌 |
|
|
39
|
+
| `"6z"` | 發 | 三元牌 |
|
|
40
|
+
| `"7z"` | 中 | 三元牌 |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 座席番号(seat)
|
|
45
|
+
|
|
46
|
+
座席は `0`〜`3` の整数で表します。局の開始時に `oya_index` で指定した座席が親(東家)となり、以降は時計回りの順です。
|
|
47
|
+
|
|
48
|
+
| seat | 自風 |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `oya_index` | 東家(親) |
|
|
51
|
+
| `oya_index + 1` | 南家 |
|
|
52
|
+
| `oya_index + 2` | 西家 |
|
|
53
|
+
| `oya_index + 3` | 北家 |
|
|
54
|
+
|
|
55
|
+
座席番号は `0`〜`3` の範囲でラップします(例:oya が 3 なら南家は 0)。
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## ゲーム進行の用語
|
|
60
|
+
|
|
61
|
+
| 用語 | 意味 |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `bakaze` | 場風(東場 = `"ton"`、南場 = `"nan"`) |
|
|
64
|
+
| `kyoku` | 局番号(1〜4)。東1局なら `kyoku: 1` |
|
|
65
|
+
| `honba` | 本場数。連荘・流局のたびに +1 |
|
|
66
|
+
| `kyoutaku` | 供託棒の枚数。リーチ棒が積まれるたびに +1 |
|
|
67
|
+
| `oya_index` | 現在の親の座席番号 |
|
|
68
|
+
| `seed` | 牌山シード。同じ seed を渡すと再現性のある牌山になる |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## アクション種別
|
|
73
|
+
|
|
74
|
+
`apply_round_action` に渡す `action` の `type` 一覧です。
|
|
75
|
+
|
|
76
|
+
### 自摸・打牌
|
|
77
|
+
|
|
78
|
+
| type | 意味 | 必須キー |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `:tsumo` | 自摸 | なし |
|
|
81
|
+
| `:dahai` | 打牌 | `seat:`, `tile:` |
|
|
82
|
+
| `:riichi` | リーチ宣言(打牌を兼ねる) | `seat:`, `tile:` |
|
|
83
|
+
| `:kyuushu_kyuuhai` | 九種九牌流局 | `seat:` |
|
|
84
|
+
|
|
85
|
+
### 鳴き・カン
|
|
86
|
+
|
|
87
|
+
| type | 意味 | 必須キー |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `:pon` | ポン | `seat:`, `tiles:` |
|
|
90
|
+
| `:chi` | チー | `seat:`, `tiles:` |
|
|
91
|
+
| `:daiminkan` | 大明槓 | `seat:` |
|
|
92
|
+
| `:ankan` | 暗槓 | `seat:`, `tile:` |
|
|
93
|
+
| `:kakan` | 加槓 | `seat:`, `tile:` |
|
|
94
|
+
|
|
95
|
+
### 和了・スキップ
|
|
96
|
+
|
|
97
|
+
| type | 意味 | 必須キー |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `:tsumo_agari` | ツモ和了 | `seat:` |
|
|
100
|
+
| `:ron_agari` | ロン和了 | `seat:` |
|
|
101
|
+
| `:skip` | パス(鳴き・ロン権を放棄) | `seat:` |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 局終了の結果種別
|
|
106
|
+
|
|
107
|
+
`RoundEndInfo#result_type` が取りうる値:
|
|
108
|
+
|
|
109
|
+
| 値 | 意味 |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `:ron` | ロン和了 |
|
|
112
|
+
| `:tsumo` | ツモ和了 |
|
|
113
|
+
| `:ryuukyoku` | 流局(荒牌) |
|
|
114
|
+
| `:kyuushu` | 九種九牌 |
|
|
115
|
+
| `:suufon_renda` | 四風連打 |
|
|
116
|
+
| `:suucha_riichi` | 四家リーチ |
|
|
117
|
+
| `:sanchahou` | 三家和 |
|
|
118
|
+
| `:suukaikan` | 四槓散了 |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 34形式(tiles_34)
|
|
123
|
+
|
|
124
|
+
`agari?` メソッドで使う内部形式です。全136枚の牌を34種×4枚で表した長さ34の整数配列です。
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
# 例: 一萬4枚 + 二萬1枚 の場合
|
|
128
|
+
tiles_34 = [4, 1, 0, 0, 0, 0, 0, 0, 0, # 萬子 1〜9
|
|
129
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, # 筒子 1〜9
|
|
130
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, # 索子 1〜9
|
|
131
|
+
0, 0, 0, 0, 0, 0, 0] # 字牌 1z〜7z
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
通常は `RoundState` や `Hand` 経由で自動的に扱われるため、直接操作する機会は `agari?` を単体テストする場面くらいです。
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 公開 API ポリシー
|
|
2
|
+
|
|
3
|
+
`riichi_engine` では、安定性を保証する公開 API と、内部実装として扱う非公開 API を明確に分けています。
|
|
4
|
+
|
|
5
|
+
host app が直接呼んでよい範囲を限定することで、gem 内部の自由な整理・リファクタリングを可能にします。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 安定 API(Stable Public Surface)
|
|
10
|
+
|
|
11
|
+
以下は host app が直接利用してよい、安定性を保証する API です。
|
|
12
|
+
|
|
13
|
+
### エントリポイント
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
RiichiEngine::API
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
局進行・和了評価・点数計算はすべてここを通してください。
|
|
20
|
+
|
|
21
|
+
### 例外
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
RiichiEngine::API::InvalidActionError
|
|
25
|
+
RiichiEngine::API::EngineError
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 値オブジェクト・設定
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Mahjong::Config::RuleConfig # ルール設定
|
|
32
|
+
Mahjong::Snapshots::* # 局情報を gem へ渡すためのスナップショット群
|
|
33
|
+
Mahjong::State::RoundState # 局状態(API の入出力として使う)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 準公開 API(Conditionally Public Domain Objects)
|
|
39
|
+
|
|
40
|
+
以下は `RiichiEngine::API` の入出力として現実的に参照することがあるため、事実上 public 扱いとします。
|
|
41
|
+
ただし、`RiichiEngine::API` の結果として受け取る形でのみ使用し、直接インスタンスを生成しないでください。
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
Mahjong::Tiles::Tile
|
|
45
|
+
Mahjong::State::Hand
|
|
46
|
+
Mahjong::Results::RoundFlowResult
|
|
47
|
+
Mahjong::Results::GameFlowResult
|
|
48
|
+
Mahjong::Results::FinalResult
|
|
49
|
+
Mahjong::Results::RoundEndInfo
|
|
50
|
+
Mahjong::Scoring::ValueObjects::ScoreResult
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
この層は大きく壊さない前提ですが、`RiichiEngine::API` ほど強い安定契約はありません。
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 内部 API(Internal Surface)
|
|
58
|
+
|
|
59
|
+
以下は host app から直接参照しないでください。
|
|
60
|
+
gem の内部責務整理・namespace 再編・最適化のために予告なく変更することがあります。
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
Mahjong::Flow::* # 局・ゲーム進行の内部処理
|
|
64
|
+
Mahjong::Scoring::* # 役判定・点数計算の実装詳細
|
|
65
|
+
Mahjong::Cpu::* # CPU AI の実装
|
|
66
|
+
Mahjong::Errors::* # EngineError / InvalidActionError 以外
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## host app が守るべきルール
|
|
72
|
+
|
|
73
|
+
1. 局進行は `RiichiEngine::API` を経由する
|
|
74
|
+
2. 和了評価は `RiichiEngine::API` を経由する
|
|
75
|
+
3. 順位計算は `RiichiEngine::API` を経由する
|
|
76
|
+
4. スナップショット生成・永続化変換は host app の adapter が担う
|
|
77
|
+
5. `Mahjong::Flow::*` や `Mahjong::Scoring::Judges::*` を service/job から直接呼ばない
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Breaking Change ポリシー
|
|
82
|
+
|
|
83
|
+
### Breaking Change とみなすもの(事前告知・メジャーバージョンアップが必要)
|
|
84
|
+
|
|
85
|
+
- `RiichiEngine::API` のメソッド削除
|
|
86
|
+
- `RiichiEngine::API` の必須引数変更
|
|
87
|
+
- `Mahjong::Snapshots::*` の必須フィールド変更
|
|
88
|
+
- `Mahjong::Config::RuleConfig` の既存キーの意味変更
|
|
89
|
+
|
|
90
|
+
### Breaking Change とみなさないもの
|
|
91
|
+
|
|
92
|
+
- 内部 namespace の移動・名前変更
|
|
93
|
+
- `Mahjong::Flow::*` / `Mahjong::Scoring::*` の整理
|
|
94
|
+
- `RiichiEngine::API` を通じた結果が同じである範囲の内部最適化
|