@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.
- package/dist/core/dora.d.ts +14 -0
- package/dist/core/dora.js +71 -0
- package/dist/core/hai.d.ts +30 -0
- package/dist/core/hai.js +78 -0
- package/dist/core/machi.d.ts +11 -0
- package/dist/core/machi.js +58 -0
- package/dist/core/mentsu.d.ts +26 -0
- package/dist/core/mentsu.js +87 -0
- package/dist/core/tehai.d.ts +42 -0
- package/dist/core/tehai.js +156 -0
- package/dist/errors.d.ts +83 -0
- package/dist/errors.js +117 -0
- package/dist/features/machi/index.d.ts +9 -0
- package/dist/features/machi/index.js +48 -0
- package/dist/features/machi/types.d.ts +1 -0
- package/dist/features/machi/types.js +1 -0
- package/dist/features/parser/index.d.ts +19 -0
- package/dist/features/parser/index.js +28 -0
- package/dist/features/parser/mspz.d.ts +85 -0
- package/dist/features/parser/mspz.js +365 -0
- package/dist/features/points/constants.d.ts +27 -0
- package/dist/features/points/constants.js +30 -0
- package/dist/features/points/index.d.ts +21 -0
- package/dist/features/points/index.js +174 -0
- package/dist/features/points/lib/fu/constants.d.ts +37 -0
- package/dist/features/points/lib/fu/constants.js +45 -0
- package/dist/features/points/lib/fu/index.d.ts +11 -0
- package/dist/features/points/lib/fu/index.js +23 -0
- package/dist/features/points/lib/fu/lib/chiitoitsu.d.ts +5 -0
- package/dist/features/points/lib/fu/lib/chiitoitsu.js +17 -0
- package/dist/features/points/lib/fu/lib/kokushi.d.ts +6 -0
- package/dist/features/points/lib/fu/lib/kokushi.js +18 -0
- package/dist/features/points/lib/fu/lib/mentsu.d.ts +11 -0
- package/dist/features/points/lib/fu/lib/mentsu.js +122 -0
- package/dist/features/points/lib/fu/types.d.ts +55 -0
- package/dist/features/points/lib/fu/types.js +1 -0
- package/dist/features/points/types.d.ts +27 -0
- package/dist/features/points/types.js +1 -0
- package/dist/features/score/constants.d.ts +27 -0
- package/dist/features/score/constants.js +30 -0
- package/dist/features/score/index.d.ts +45 -0
- package/dist/features/score/index.js +207 -0
- package/dist/features/score/lib/fu/constants.d.ts +37 -0
- package/dist/features/score/lib/fu/constants.js +45 -0
- package/dist/features/score/lib/fu/index.d.ts +11 -0
- package/dist/features/score/lib/fu/index.js +23 -0
- package/dist/features/score/lib/fu/lib/chiitoitsu.d.ts +5 -0
- package/dist/features/score/lib/fu/lib/chiitoitsu.js +17 -0
- package/dist/features/score/lib/fu/lib/kokushi.d.ts +6 -0
- package/dist/features/score/lib/fu/lib/kokushi.js +18 -0
- package/dist/features/score/lib/fu/lib/mentsu.d.ts +11 -0
- package/dist/features/score/lib/fu/lib/mentsu.js +136 -0
- package/dist/features/score/lib/fu/types.d.ts +56 -0
- package/dist/features/score/lib/fu/types.js +1 -0
- package/dist/features/score/types.d.ts +78 -0
- package/dist/features/score/types.js +22 -0
- package/dist/features/shanten/index.d.ts +16 -0
- package/dist/features/shanten/index.js +25 -0
- package/dist/features/shanten/logic/chiitoitsu.d.ts +8 -0
- package/dist/features/shanten/logic/chiitoitsu.js +36 -0
- package/dist/features/shanten/logic/kokushi.d.ts +16 -0
- package/dist/features/shanten/logic/kokushi.js +48 -0
- package/dist/features/shanten/logic/mentsu-te.d.ts +8 -0
- package/dist/features/shanten/logic/mentsu-te.js +129 -0
- package/dist/features/yaku/factory.d.ts +13 -0
- package/dist/features/yaku/factory.js +19 -0
- package/dist/features/yaku/index.d.ts +21 -0
- package/dist/features/yaku/index.js +59 -0
- package/dist/features/yaku/lib/definitions/chiitoitsu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/chiitoitsu.js +12 -0
- package/dist/features/yaku/lib/definitions/chinitsu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/chinitsu.js +40 -0
- package/dist/features/yaku/lib/definitions/chinroutou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/chinroutou.js +21 -0
- package/dist/features/yaku/lib/definitions/chuuren-poutou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/chuuren-poutou.js +69 -0
- package/dist/features/yaku/lib/definitions/daisangen.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/daisangen.js +26 -0
- package/dist/features/yaku/lib/definitions/daisuushii.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/daisuushii.js +32 -0
- package/dist/features/yaku/lib/definitions/honchan.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/honchan.js +29 -0
- package/dist/features/yaku/lib/definitions/honitsu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/honitsu.js +40 -0
- package/dist/features/yaku/lib/definitions/honroutou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/honroutou.js +33 -0
- package/dist/features/yaku/lib/definitions/iipeikou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/iipeikou.js +46 -0
- package/dist/features/yaku/lib/definitions/ikkitsuukan.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/ikkitsuukan.js +56 -0
- package/dist/features/yaku/lib/definitions/index.d.ts +30 -0
- package/dist/features/yaku/lib/definitions/index.js +90 -0
- package/dist/features/yaku/lib/definitions/junchan.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/junchan.js +25 -0
- package/dist/features/yaku/lib/definitions/kokushi.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/kokushi.js +12 -0
- package/dist/features/yaku/lib/definitions/menzen-tsumo.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/menzen-tsumo.js +8 -0
- package/dist/features/yaku/lib/definitions/pinfu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/pinfu.js +40 -0
- package/dist/features/yaku/lib/definitions/ryanpeikou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/ryanpeikou.js +33 -0
- package/dist/features/yaku/lib/definitions/ryuuiisou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/ryuuiisou.js +43 -0
- package/dist/features/yaku/lib/definitions/sanankou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/sanankou.js +49 -0
- package/dist/features/yaku/lib/definitions/sankantsu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/sankantsu.js +18 -0
- package/dist/features/yaku/lib/definitions/sanshoku-doujun.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/sanshoku-doujun.js +58 -0
- package/dist/features/yaku/lib/definitions/sanshoku-doukou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/sanshoku-doukou.js +53 -0
- package/dist/features/yaku/lib/definitions/shousangen.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/shousangen.js +28 -0
- package/dist/features/yaku/lib/definitions/shousuushii.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/shousuushii.js +34 -0
- package/dist/features/yaku/lib/definitions/suuankou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/suuankou.js +63 -0
- package/dist/features/yaku/lib/definitions/suukantsu.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/suukantsu.js +18 -0
- package/dist/features/yaku/lib/definitions/tanyao.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/tanyao.js +23 -0
- package/dist/features/yaku/lib/definitions/toitoi.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/toitoi.js +16 -0
- package/dist/features/yaku/lib/definitions/tsuuiisou.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/tsuuiisou.js +35 -0
- package/dist/features/yaku/lib/definitions/yakuhai.d.ts +4 -0
- package/dist/features/yaku/lib/definitions/yakuhai.js +21 -0
- package/dist/features/yaku/lib/index.d.ts +1 -0
- package/dist/features/yaku/lib/index.js +1 -0
- package/dist/features/yaku/lib/structures/chiitoitsu.d.ts +6 -0
- package/dist/features/yaku/lib/structures/chiitoitsu.js +38 -0
- package/dist/features/yaku/lib/structures/index.d.ts +10 -0
- package/dist/features/yaku/lib/structures/index.js +17 -0
- package/dist/features/yaku/lib/structures/kokushi.d.ts +6 -0
- package/dist/features/yaku/lib/structures/kokushi.js +43 -0
- package/dist/features/yaku/lib/structures/mentsu-te.d.ts +24 -0
- package/dist/features/yaku/lib/structures/mentsu-te.js +127 -0
- package/dist/features/yaku/types.d.ts +121 -0
- package/dist/features/yaku/types.js +1 -0
- package/dist/features/yaku/utils.d.ts +19 -0
- package/dist/features/yaku/utils.js +34 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +53 -0
- package/dist/types.d.ts +290 -0
- package/dist/types.js +97 -0
- package/dist/utils/assertions.d.ts +22 -0
- package/dist/utils/assertions.js +33 -0
- package/dist/utils/test-helpers.d.ts +55 -0
- package/dist/utils/test-helpers.js +124 -0
- 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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -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";
|