@pai-forge/riichi-mahjong 0.2.0 → 0.3.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.
Files changed (151) hide show
  1. package/dist/core/dora.d.ts +14 -0
  2. package/dist/core/dora.js +71 -0
  3. package/dist/core/hai.d.ts +30 -0
  4. package/dist/core/hai.js +78 -0
  5. package/dist/core/machi.d.ts +11 -0
  6. package/dist/core/machi.js +58 -0
  7. package/dist/core/mentsu.d.ts +26 -0
  8. package/dist/core/mentsu.js +87 -0
  9. package/dist/core/tehai.d.ts +42 -0
  10. package/dist/core/tehai.js +156 -0
  11. package/dist/errors.d.ts +83 -0
  12. package/dist/errors.js +117 -0
  13. package/dist/features/machi/index.d.ts +9 -0
  14. package/dist/features/machi/index.js +48 -0
  15. package/dist/features/machi/types.d.ts +1 -0
  16. package/dist/features/machi/types.js +1 -0
  17. package/dist/features/parser/index.d.ts +19 -0
  18. package/dist/features/parser/index.js +28 -0
  19. package/dist/features/parser/mspz.d.ts +85 -0
  20. package/dist/features/parser/mspz.js +365 -0
  21. package/dist/features/points/constants.d.ts +27 -0
  22. package/dist/features/points/constants.js +30 -0
  23. package/dist/features/points/index.d.ts +21 -0
  24. package/dist/features/points/index.js +174 -0
  25. package/dist/features/points/lib/fu/constants.d.ts +37 -0
  26. package/dist/features/points/lib/fu/constants.js +45 -0
  27. package/dist/features/points/lib/fu/index.d.ts +11 -0
  28. package/dist/features/points/lib/fu/index.js +23 -0
  29. package/dist/features/points/lib/fu/lib/chiitoitsu.d.ts +5 -0
  30. package/dist/features/points/lib/fu/lib/chiitoitsu.js +17 -0
  31. package/dist/features/points/lib/fu/lib/kokushi.d.ts +6 -0
  32. package/dist/features/points/lib/fu/lib/kokushi.js +18 -0
  33. package/dist/features/points/lib/fu/lib/mentsu.d.ts +11 -0
  34. package/dist/features/points/lib/fu/lib/mentsu.js +122 -0
  35. package/dist/features/points/lib/fu/types.d.ts +55 -0
  36. package/dist/features/points/lib/fu/types.js +1 -0
  37. package/dist/features/points/types.d.ts +27 -0
  38. package/dist/features/points/types.js +1 -0
  39. package/dist/features/score/constants.d.ts +27 -0
  40. package/dist/features/score/constants.js +30 -0
  41. package/dist/features/score/index.d.ts +45 -0
  42. package/dist/features/score/index.js +207 -0
  43. package/dist/features/score/lib/fu/constants.d.ts +37 -0
  44. package/dist/features/score/lib/fu/constants.js +45 -0
  45. package/dist/features/score/lib/fu/index.d.ts +11 -0
  46. package/dist/features/score/lib/fu/index.js +23 -0
  47. package/dist/features/score/lib/fu/lib/chiitoitsu.d.ts +5 -0
  48. package/dist/features/score/lib/fu/lib/chiitoitsu.js +17 -0
  49. package/dist/features/score/lib/fu/lib/kokushi.d.ts +6 -0
  50. package/dist/features/score/lib/fu/lib/kokushi.js +18 -0
  51. package/dist/features/score/lib/fu/lib/mentsu.d.ts +11 -0
  52. package/dist/features/score/lib/fu/lib/mentsu.js +136 -0
  53. package/dist/features/score/lib/fu/types.d.ts +56 -0
  54. package/dist/features/score/lib/fu/types.js +1 -0
  55. package/dist/features/score/types.d.ts +78 -0
  56. package/dist/features/score/types.js +22 -0
  57. package/dist/features/shanten/index.d.ts +16 -0
  58. package/dist/features/shanten/index.js +25 -0
  59. package/dist/features/shanten/logic/chiitoitsu.d.ts +8 -0
  60. package/dist/features/shanten/logic/chiitoitsu.js +36 -0
  61. package/dist/features/shanten/logic/kokushi.d.ts +16 -0
  62. package/dist/features/shanten/logic/kokushi.js +48 -0
  63. package/dist/features/shanten/logic/mentsu-te.d.ts +8 -0
  64. package/dist/features/shanten/logic/mentsu-te.js +129 -0
  65. package/dist/features/yaku/factory.d.ts +13 -0
  66. package/dist/features/yaku/factory.js +19 -0
  67. package/dist/features/yaku/index.d.ts +21 -0
  68. package/dist/features/yaku/index.js +59 -0
  69. package/dist/features/yaku/lib/definitions/chiitoitsu.d.ts +2 -0
  70. package/dist/features/yaku/lib/definitions/chiitoitsu.js +12 -0
  71. package/dist/features/yaku/lib/definitions/chinitsu.d.ts +2 -0
  72. package/dist/features/yaku/lib/definitions/chinitsu.js +40 -0
  73. package/dist/features/yaku/lib/definitions/chinroutou.d.ts +2 -0
  74. package/dist/features/yaku/lib/definitions/chinroutou.js +21 -0
  75. package/dist/features/yaku/lib/definitions/chuuren-poutou.d.ts +2 -0
  76. package/dist/features/yaku/lib/definitions/chuuren-poutou.js +69 -0
  77. package/dist/features/yaku/lib/definitions/daisangen.d.ts +2 -0
  78. package/dist/features/yaku/lib/definitions/daisangen.js +26 -0
  79. package/dist/features/yaku/lib/definitions/daisuushii.d.ts +2 -0
  80. package/dist/features/yaku/lib/definitions/daisuushii.js +32 -0
  81. package/dist/features/yaku/lib/definitions/honchan.d.ts +2 -0
  82. package/dist/features/yaku/lib/definitions/honchan.js +29 -0
  83. package/dist/features/yaku/lib/definitions/honitsu.d.ts +2 -0
  84. package/dist/features/yaku/lib/definitions/honitsu.js +40 -0
  85. package/dist/features/yaku/lib/definitions/honroutou.d.ts +2 -0
  86. package/dist/features/yaku/lib/definitions/honroutou.js +33 -0
  87. package/dist/features/yaku/lib/definitions/iipeikou.d.ts +2 -0
  88. package/dist/features/yaku/lib/definitions/iipeikou.js +46 -0
  89. package/dist/features/yaku/lib/definitions/ikkitsuukan.d.ts +2 -0
  90. package/dist/features/yaku/lib/definitions/ikkitsuukan.js +56 -0
  91. package/dist/features/yaku/lib/definitions/index.d.ts +30 -0
  92. package/dist/features/yaku/lib/definitions/index.js +90 -0
  93. package/dist/features/yaku/lib/definitions/junchan.d.ts +2 -0
  94. package/dist/features/yaku/lib/definitions/junchan.js +25 -0
  95. package/dist/features/yaku/lib/definitions/kokushi.d.ts +2 -0
  96. package/dist/features/yaku/lib/definitions/kokushi.js +12 -0
  97. package/dist/features/yaku/lib/definitions/menzen-tsumo.d.ts +2 -0
  98. package/dist/features/yaku/lib/definitions/menzen-tsumo.js +8 -0
  99. package/dist/features/yaku/lib/definitions/pinfu.d.ts +2 -0
  100. package/dist/features/yaku/lib/definitions/pinfu.js +40 -0
  101. package/dist/features/yaku/lib/definitions/ryanpeikou.d.ts +2 -0
  102. package/dist/features/yaku/lib/definitions/ryanpeikou.js +33 -0
  103. package/dist/features/yaku/lib/definitions/ryuuiisou.d.ts +2 -0
  104. package/dist/features/yaku/lib/definitions/ryuuiisou.js +43 -0
  105. package/dist/features/yaku/lib/definitions/sanankou.d.ts +2 -0
  106. package/dist/features/yaku/lib/definitions/sanankou.js +49 -0
  107. package/dist/features/yaku/lib/definitions/sankantsu.d.ts +2 -0
  108. package/dist/features/yaku/lib/definitions/sankantsu.js +18 -0
  109. package/dist/features/yaku/lib/definitions/sanshoku-doujun.d.ts +2 -0
  110. package/dist/features/yaku/lib/definitions/sanshoku-doujun.js +58 -0
  111. package/dist/features/yaku/lib/definitions/sanshoku-doukou.d.ts +2 -0
  112. package/dist/features/yaku/lib/definitions/sanshoku-doukou.js +53 -0
  113. package/dist/features/yaku/lib/definitions/shousangen.d.ts +2 -0
  114. package/dist/features/yaku/lib/definitions/shousangen.js +28 -0
  115. package/dist/features/yaku/lib/definitions/shousuushii.d.ts +2 -0
  116. package/dist/features/yaku/lib/definitions/shousuushii.js +34 -0
  117. package/dist/features/yaku/lib/definitions/suuankou.d.ts +2 -0
  118. package/dist/features/yaku/lib/definitions/suuankou.js +63 -0
  119. package/dist/features/yaku/lib/definitions/suukantsu.d.ts +2 -0
  120. package/dist/features/yaku/lib/definitions/suukantsu.js +18 -0
  121. package/dist/features/yaku/lib/definitions/tanyao.d.ts +2 -0
  122. package/dist/features/yaku/lib/definitions/tanyao.js +23 -0
  123. package/dist/features/yaku/lib/definitions/toitoi.d.ts +2 -0
  124. package/dist/features/yaku/lib/definitions/toitoi.js +16 -0
  125. package/dist/features/yaku/lib/definitions/tsuuiisou.d.ts +2 -0
  126. package/dist/features/yaku/lib/definitions/tsuuiisou.js +35 -0
  127. package/dist/features/yaku/lib/definitions/yakuhai.d.ts +4 -0
  128. package/dist/features/yaku/lib/definitions/yakuhai.js +21 -0
  129. package/dist/features/yaku/lib/index.d.ts +1 -0
  130. package/dist/features/yaku/lib/index.js +1 -0
  131. package/dist/features/yaku/lib/structures/chiitoitsu.d.ts +6 -0
  132. package/dist/features/yaku/lib/structures/chiitoitsu.js +38 -0
  133. package/dist/features/yaku/lib/structures/index.d.ts +10 -0
  134. package/dist/features/yaku/lib/structures/index.js +17 -0
  135. package/dist/features/yaku/lib/structures/kokushi.d.ts +6 -0
  136. package/dist/features/yaku/lib/structures/kokushi.js +43 -0
  137. package/dist/features/yaku/lib/structures/mentsu-te.d.ts +24 -0
  138. package/dist/features/yaku/lib/structures/mentsu-te.js +127 -0
  139. package/dist/features/yaku/types.d.ts +121 -0
  140. package/dist/features/yaku/types.js +1 -0
  141. package/dist/features/yaku/utils.d.ts +19 -0
  142. package/dist/features/yaku/utils.js +34 -0
  143. package/dist/index.d.ts +21 -0
  144. package/dist/index.js +53 -0
  145. package/dist/types.d.ts +290 -0
  146. package/dist/types.js +97 -0
  147. package/dist/utils/assertions.d.ts +22 -0
  148. package/dist/utils/assertions.js +33 -0
  149. package/dist/utils/test-helpers.d.ts +55 -0
  150. package/dist/utils/test-helpers.js +124 -0
  151. package/package.json +3 -2
@@ -0,0 +1,24 @@
1
+ import type { MentsuHouraStructure } from "../../types";
2
+ import type { Tehai14 } from "../../../../types";
3
+ /**
4
+ * 手牌を標準形(4面子1雀頭)に構造化する。
5
+ * 七対子や国士無双は対象外。
6
+ *
7
+ * 【役判定について】
8
+ * この関数は純粋に「4面子1雀頭」の形になっているかのみを検証します。
9
+ * 役が成立しているかどうか(和了できるかどうか)は判定しません。
10
+ * そのため、役なし(Yakunashi)の手牌であっても構造的に整合していれば結果を返します。
11
+ *
12
+ * 【戻り値が配列である理由について】
13
+ * 麻雀の手牌は、同じ牌構成であっても複数の解釈(多義性)が成立する場合があります。
14
+ * 例: `111222333m`
15
+ * - 三暗刻 (111 + 222 + 333)
16
+ * - 三連刻/一盃口 (123 + 123 + 123)
17
+ *
18
+ * このように成立する役が変わる可能性があるため、可能な全ての構造化パターンをリストとして返します。
19
+ * 利用側は、これらのパターンのうち最も高得点となるものを選択する必要があります。
20
+ *
21
+ * @param tehai 和了形の手牌
22
+ * @returns 可能な構造化パターンのリスト。構造化できない場合は空配列。
23
+ */
24
+ export declare function getHouraStructuresForMentsuTe(tehai: Tehai14): MentsuHouraStructure[];
@@ -0,0 +1,127 @@
1
+ import { validateTehai14, countHaiKind } from "../../../../core/tehai";
2
+ import { isTuple4 } from "../../../../utils/assertions";
3
+ /**
4
+ * 手牌を標準形(4面子1雀頭)に構造化する。
5
+ * 七対子や国士無双は対象外。
6
+ *
7
+ * 【役判定について】
8
+ * この関数は純粋に「4面子1雀頭」の形になっているかのみを検証します。
9
+ * 役が成立しているかどうか(和了できるかどうか)は判定しません。
10
+ * そのため、役なし(Yakunashi)の手牌であっても構造的に整合していれば結果を返します。
11
+ *
12
+ * 【戻り値が配列である理由について】
13
+ * 麻雀の手牌は、同じ牌構成であっても複数の解釈(多義性)が成立する場合があります。
14
+ * 例: `111222333m`
15
+ * - 三暗刻 (111 + 222 + 333)
16
+ * - 三連刻/一盃口 (123 + 123 + 123)
17
+ *
18
+ * このように成立する役が変わる可能性があるため、可能な全ての構造化パターンをリストとして返します。
19
+ * 利用側は、これらのパターンのうち最も高得点となるものを選択する必要があります。
20
+ *
21
+ * @param tehai 和了形の手牌
22
+ * @returns 可能な構造化パターンのリスト。構造化できない場合は空配列。
23
+ */
24
+ export function getHouraStructuresForMentsuTe(tehai) {
25
+ validateTehai14(tehai);
26
+ // HaiKindDistributionはreadonlyなので、可変配列に複製する
27
+ const counts = [...countHaiKind(tehai.closed)];
28
+ const results = [];
29
+ // 1. 雀頭候補を探す
30
+ for (let i = 0; i < 34; i++) {
31
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
32
+ const kind = i;
33
+ if ((counts[kind] ?? 0) >= 2) {
34
+ // 雀頭抜き出し
35
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
36
+ counts[kind] -= 2;
37
+ // 残りの牌で面子分解
38
+ const requiredMentsuCount = 4 - tehai.exposed.length;
39
+ const subResults = decomposeClosedMentsu(counts, requiredMentsuCount);
40
+ // subResultsには閉じた部分で見つかった面子のリストが含まれる
41
+ for (const closedMentsu of subResults) {
42
+ // 副露面子と結合して完全な構成を作成する
43
+ const fullMentsuList = [...closedMentsu, ...tehai.exposed];
44
+ // 4面子であることを確認(ロジック上は保証されているはずだが、念のため)
45
+ if (isTuple4(fullMentsuList)) {
46
+ results.push({
47
+ type: "Mentsu",
48
+ fourMentsu: fullMentsuList,
49
+ jantou: { type: "Toitsu", hais: [kind, kind] },
50
+ });
51
+ }
52
+ }
53
+ // バックトラック
54
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
55
+ counts[kind] += 2;
56
+ }
57
+ }
58
+ return results;
59
+ }
60
+ /**
61
+ * 閉じた手牌の残りを面子に分解する再帰関数
62
+ */
63
+ function decomposeClosedMentsu(
64
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
65
+ counts, requiredCount) {
66
+ if (requiredCount === 0) {
67
+ // 全ての牌が使用されたか確認
68
+ const remaining = counts.reduce((acc, c) => acc + c, 0);
69
+ return remaining === 0 ? [[]] : [];
70
+ }
71
+ // 面子の重複順列を防ぎ決定論的な順序を強制するため、カウントが0より大きい最初の牌を見つける
72
+ let firstIndex = -1;
73
+ for (let i = 0; i < 34; i++) {
74
+ if ((counts[i] ?? 0) > 0) {
75
+ firstIndex = i;
76
+ break;
77
+ }
78
+ }
79
+ if (firstIndex === -1) {
80
+ // Should not happen if requiredCount > 0, unless invalid hand
81
+ return [];
82
+ }
83
+ const results = [];
84
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
85
+ const kind = firstIndex;
86
+ // 刻子を試す
87
+ if ((counts[kind] ?? 0) >= 3) {
88
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
89
+ counts[kind] -= 3;
90
+ const tails = decomposeClosedMentsu(counts, requiredCount - 1);
91
+ const koutsu = { type: "Koutsu", hais: [kind, kind, kind] };
92
+ for (const tail of tails) {
93
+ results.push([koutsu, ...tail]);
94
+ }
95
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
96
+ counts[kind] += 3; // バックトラック
97
+ }
98
+ // 順子を試す
99
+ // 数牌(0-26)かつ7を超えない(n, n+1, n+2を作れる)場合のみ有効
100
+ if (kind < 27 && kind % 9 <= 6) {
101
+ const k1 = kind;
102
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
103
+ const k2 = (kind + 1);
104
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
105
+ const k3 = (kind + 2);
106
+ if ((counts[k2] ?? 0) > 0 && (counts[k3] ?? 0) > 0) {
107
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
108
+ counts[k1] -= 1;
109
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
110
+ counts[k2] -= 1;
111
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ counts[k3] -= 1;
113
+ const tails = decomposeClosedMentsu(counts, requiredCount - 1);
114
+ const shuntsu = { type: "Shuntsu", hais: [k1, k2, k3] };
115
+ for (const tail of tails) {
116
+ results.push([shuntsu, ...tail]);
117
+ }
118
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
119
+ counts[k1] += 1;
120
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
121
+ counts[k2] += 1;
122
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
123
+ counts[k3] += 1; // バックトラック
124
+ }
125
+ }
126
+ return results;
127
+ }
@@ -0,0 +1,121 @@
1
+ import type { HaiKindId, Kazehai, Shuntsu, Koutsu, Kantsu, Toitsu, Mentsu, CompletedMentsu } from "../../types";
2
+ export type { Kazehai, Shuntsu, Koutsu, Kantsu, Toitsu, Mentsu };
3
+ /**
4
+ * 役牌 (Yakuhai)
5
+ *
6
+ * 構造的に成立する三元牌。
7
+ * ※場風・自風は状況役(Bakaze, Jikaze)として別途定義するためここには含めない。
8
+ */
9
+ export type Yakuhai = "Haku" | "Hatsu" | "Chun";
10
+ /**
11
+ * 手牌役 (TehaiYaku)
12
+ *
13
+ * 手牌役(手牌の構成のみで成立する役)の識別子。
14
+ * 偶然役(嶺上開花など)や状況役(場風、自風、立直など)は含まない。
15
+ */
16
+ export type TehaiYaku = "Tanyao" | "Pinfu" | "Iipeikou" | Yakuhai | "SanshokuDoujun" | "Ikkitsuukan" | "Honchan" | "Chiitoitsu" | "Toitoi" | "Sanankou" | "Sankantsu" | "SanshokuDoukou" | "Honroutou" | "Shousangen" | "Honitsu" | "Junchan" | "Ryanpeikou" | "Chinitsu" | "KokushiMusou" | "Suuankou" | "Daisangen" | "Shousuushii" | "Daisuushii" | "Tsuuiisou" | "Chinroutou" | "Ryuuiisou" | "ChuurenPoutou" | "Suukantsu" | "MenzenTsumo";
17
+ /**
18
+ * 役の翻数 (Hansu)
19
+ *
20
+ * 1, 2, 3, 5(流し満貫/清一色喰い下がり), 6(清一色), 13(役満), 26(ダブル役満)
21
+ */
22
+ export type Hansu = 1 | 2 | 3 | 5 | 6 | 13 | 26;
23
+ export interface MentsuHouraStructure {
24
+ readonly type: "Mentsu";
25
+ readonly fourMentsu: readonly [
26
+ CompletedMentsu,
27
+ CompletedMentsu,
28
+ CompletedMentsu,
29
+ CompletedMentsu
30
+ ];
31
+ readonly jantou: Toitsu;
32
+ }
33
+ export interface ChiitoitsuHouraStructure {
34
+ readonly type: "Chiitoitsu";
35
+ readonly pairs: readonly [
36
+ Toitsu,
37
+ Toitsu,
38
+ Toitsu,
39
+ Toitsu,
40
+ Toitsu,
41
+ Toitsu,
42
+ Toitsu
43
+ ];
44
+ }
45
+ export interface KokushiHouraStructure {
46
+ readonly type: "Kokushi";
47
+ /** 13種類の么九牌(重複なし) */
48
+ readonly yaochu: readonly HaiKindId[];
49
+ /** 雀頭となる牌の種類 */
50
+ readonly jantou: HaiKindId;
51
+ }
52
+ export type HouraStructure = MentsuHouraStructure | ChiitoitsuHouraStructure | KokushiHouraStructure;
53
+ /**
54
+ * 役の翻数定義
55
+ */
56
+ export interface YakuHanConfig {
57
+ /** 門前時の翻数 */
58
+ readonly closed: Hansu;
59
+ /**
60
+ * 鳴きあり時の翻数 (0なら不成立)
61
+ *
62
+ * @remarks
63
+ * この値が 0 の場合、その役は**門前限定(Menzen-only)**であることを意味します。
64
+ * 役判定ロジックにおいては、この値が 0 でかつ手牌が副露されている場合、
65
+ * 役の条件を満たしていても不成立とみなされます。
66
+ */
67
+ readonly open: Hansu | 0;
68
+ }
69
+ /**
70
+ * 役ID (YakuName)
71
+ *
72
+ * 全ての役の識別子ユニオン。
73
+ */
74
+ export type YakuName = TehaiYaku;
75
+ /**
76
+ * 役判定結果 (YakuResult)
77
+ *
78
+ * 成立した役と、その翻数のペアのリスト。
79
+ * 役が一つも成立しない場合は空配列となる。
80
+ */
81
+ export type YakuResult = readonly [YakuName, Hansu][];
82
+ export interface HouraContext {
83
+ /** 手牌が門前かどうか(暗槓が含まれていても門前扱い) */
84
+ readonly isMenzen: boolean;
85
+ /** 和了牌(平和判定などに必要)。省略時は判定不能な役がある */
86
+ readonly agariHai: HaiKindId;
87
+ /** 場風牌 */
88
+ readonly bakaze?: Kazehai | undefined;
89
+ /** 自風牌 */
90
+ readonly jikaze?: Kazehai | undefined;
91
+ /** ツモ和了かどうか(暗刻系役の判定などに使用) */
92
+ readonly isTsumo?: boolean | undefined;
93
+ /**
94
+ * ドラ表示牌 (表ドラ) のリスト
95
+ */
96
+ readonly doraMarkers: readonly HaiKindId[];
97
+ /**
98
+ * 裏ドラ表示牌のリスト (リーチ時のみ有効)
99
+ */
100
+ readonly uraDoraMarkers?: readonly HaiKindId[];
101
+ }
102
+ export interface Yaku {
103
+ readonly name: YakuName;
104
+ /** 翻数 (喰い下がり考慮) */
105
+ readonly han: {
106
+ readonly open: Hansu | 0;
107
+ readonly closed: Hansu;
108
+ };
109
+ }
110
+ /**
111
+ * 役の成立判定関数
112
+ * @param hand 分解された手牌構造
113
+ * @param context 判定コンテキスト
114
+ * @returns 成立回数 (0なら不成立、役牌などで複数成立しうる)
115
+ */
116
+ export type YakuCheck = (hand: HouraStructure, context: HouraContext) => number;
117
+ export interface YakuDefinition {
118
+ readonly yaku: Yaku;
119
+ readonly isSatisfied: (hand: HouraStructure, context: HouraContext) => boolean;
120
+ readonly getHansu: (hand: HouraStructure, context: HouraContext) => Hansu | 0;
121
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { type HaiKindId, type Kazehai, type Tehai14 } from "../../types";
2
+ /**
3
+ * 手牌が門前(メンゼン)かどうかを判定する。
4
+ *
5
+ * 門前の定義:
6
+ * - 明刻、明順、明槓などの「晒し」が含まれていないこと。
7
+ * - 暗槓は門前として扱う。
8
+ *
9
+ * @param tehai 判定対象の手牌
10
+ * @returns 門前であれば true、そうでなければ false
11
+ */
12
+ export declare function isMenzen(tehai: Tehai14): boolean;
13
+ /**
14
+ * 指定された牌が風牌かどうかを判定する。
15
+ *
16
+ * @param id 判定対象の牌種ID
17
+ * @returns 風牌(東・南・西・北)であれば true
18
+ */
19
+ export declare function isKazehai(id: HaiKindId): id is Kazehai;
@@ -0,0 +1,34 @@
1
+ import { HaiKind, } from "../../types";
2
+ /**
3
+ * 手牌が門前(メンゼン)かどうかを判定する。
4
+ *
5
+ * 門前の定義:
6
+ * - 明刻、明順、明槓などの「晒し」が含まれていないこと。
7
+ * - 暗槓は門前として扱う。
8
+ *
9
+ * @param tehai 判定対象の手牌
10
+ * @returns 門前であれば true、そうでなければ false
11
+ */
12
+ export function isMenzen(tehai) {
13
+ // exposed(副露ブロック)が空なら門前
14
+ if (tehai.exposed.length === 0) {
15
+ return true;
16
+ }
17
+ // 副露ブロックがある場合、全てが「暗槓」であれば門前とみなす
18
+ // 暗槓の定義: typeが"Kantsu"かつfuro情報を持たない(現状のデータ構造における定義)
19
+ return tehai.exposed.every((m) => {
20
+ return m.type === "Kantsu" && !m.furo;
21
+ });
22
+ }
23
+ /**
24
+ * 指定された牌が風牌かどうかを判定する。
25
+ *
26
+ * @param id 判定対象の牌種ID
27
+ * @returns 風牌(東・南・西・北)であれば true
28
+ */
29
+ export function isKazehai(id) {
30
+ return (id === HaiKind.Ton ||
31
+ id === HaiKind.Nan ||
32
+ id === HaiKind.Sha ||
33
+ id === HaiKind.Pei);
34
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Riichi Mahjong Library
3
+ */
4
+ export { HaiKind, Tacha, FuroType, MentsuType, HaiType } from "./types";
5
+ export type { HaiId, HaiKindId, Furo, Shuntsu, Koutsu, Kantsu, CompletedMentsu, Tehai, Tehai13, Tehai14, Mentsu, IncompletedMentsu, Kazehai, Fu, } from "./types";
6
+ export type { YakuResult, YakuName, Hansu } from "./features/yaku";
7
+ export type { ScoreResult, ScoreCalculationConfig, Payment, Ron, KoTsumo, OyaTsumo, } from "./features/score/types";
8
+ export { MahjongError, ShoushaiError, TahaiError, MahjongArgumentError, DuplicatedHaiIdError, InvalidHaiQuantityError, ChomboError, NoYakuError, } from "./errors";
9
+ export { haiIdToKindId, kindIdToHaiType, haiKindToNumber, isSuupai, isYaochu, YAOCHU_KIND_IDS, } from "./core/hai";
10
+ export { validateTehai, isTehai13, isTehai14 } from "./core/tehai";
11
+ export { isValidShuntsu, isValidKoutsu, isValidKantsu, isValidToitsu, isValidTatsu, } from "./core/mentsu";
12
+ export { getDoraNext, countDora } from "./core/dora";
13
+ export { classifyMachi } from "./core/machi";
14
+ export type { MachiType } from "./core/machi";
15
+ export { calculateShanten } from "./features/shanten";
16
+ export { getUkeire } from "./features/machi";
17
+ export { detectYaku } from "./features/yaku";
18
+ export { isMenzen, isKazehai } from "./features/yaku/utils";
19
+ export { parseMspz, parseExtendedMspz } from "./features/parser";
20
+ export { isMspz, isExtendedMspz } from "./features/parser/mspz";
21
+ export { calculateScoreForTehai, getPaymentTotal } from "./features/score";
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Riichi Mahjong Library
3
+ */
4
+ // =============================================================================
5
+ // Types & Constants
6
+ // =============================================================================
7
+ export { HaiKind, Tacha, FuroType, MentsuType, HaiType } from "./types";
8
+ // =============================================================================
9
+ // Errors
10
+ // =============================================================================
11
+ export { MahjongError, ShoushaiError, TahaiError, MahjongArgumentError, DuplicatedHaiIdError, InvalidHaiQuantityError, ChomboError, NoYakuError, } from "./errors";
12
+ // =============================================================================
13
+ // Core - Hai (Tile) Utilities
14
+ // =============================================================================
15
+ export { haiIdToKindId, kindIdToHaiType, haiKindToNumber, isSuupai, isYaochu, YAOCHU_KIND_IDS, } from "./core/hai";
16
+ // =============================================================================
17
+ // Core - Tehai (Hand) Validation
18
+ // =============================================================================
19
+ export { validateTehai, isTehai13, isTehai14 } from "./core/tehai";
20
+ // =============================================================================
21
+ // Core - Mentsu (Meld) Validation
22
+ // =============================================================================
23
+ export { isValidShuntsu, isValidKoutsu, isValidKantsu, isValidToitsu, isValidTatsu, } from "./core/mentsu";
24
+ // =============================================================================
25
+ // Core - Dora
26
+ // =============================================================================
27
+ export { getDoraNext, countDora } from "./core/dora";
28
+ // =============================================================================
29
+ // Core - Machi (Wait) Classification
30
+ // =============================================================================
31
+ export { classifyMachi } from "./core/machi";
32
+ // =============================================================================
33
+ // Features - Shanten
34
+ // =============================================================================
35
+ export { calculateShanten } from "./features/shanten";
36
+ // =============================================================================
37
+ // Features - Machi
38
+ // =============================================================================
39
+ export { getUkeire } from "./features/machi";
40
+ // =============================================================================
41
+ // Features - Yaku
42
+ // =============================================================================
43
+ export { detectYaku } from "./features/yaku";
44
+ export { isMenzen, isKazehai } from "./features/yaku/utils";
45
+ // =============================================================================
46
+ // Features - Parser
47
+ // =============================================================================
48
+ export { parseMspz, parseExtendedMspz } from "./features/parser";
49
+ export { isMspz, isExtendedMspz } from "./features/parser/mspz";
50
+ // =============================================================================
51
+ // Features - Score
52
+ // =============================================================================
53
+ export { calculateScoreForTehai, getPaymentTotal } from "./features/score";