@pai-forge/riichi-mahjong 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.
- package/README.md +58 -0
- 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 +38 -0
- package/dist/core/tehai.js +87 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.js +58 -0
- package/dist/features/machi/index.d.ts +9 -0
- package/dist/features/machi/index.js +37 -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/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 +12 -0
- package/dist/features/yaku/index.js +62 -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/iipeiko.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/iipeiko.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/ryanpeiko.d.ts +2 -0
- package/dist/features/yaku/lib/definitions/ryanpeiko.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 +12 -0
- package/dist/index.js +9 -0
- package/dist/types.d.ts +280 -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 +62 -0
|
@@ -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,12 @@
|
|
|
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, } from "./types";
|
|
6
|
+
export type { YakuResult, YakuName, Hansu } from "./features/yaku";
|
|
7
|
+
export { calculateShanten } from "./features/shanten";
|
|
8
|
+
export { getUkeire } from "./features/machi";
|
|
9
|
+
export { detectYaku } from "./features/yaku";
|
|
10
|
+
export { parseMspz, parseExtendedMspz } from "./features/parser";
|
|
11
|
+
export { calculateScore } from "./features/points";
|
|
12
|
+
export type { ScoreResult, ScoreLevel, ScorePayment, ScoreCalculationConfig, } from "./features/points/types";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Riichi Mahjong Library
|
|
3
|
+
*/
|
|
4
|
+
export { HaiKind, Tacha, FuroType, MentsuType, HaiType } from "./types";
|
|
5
|
+
export { calculateShanten } from "./features/shanten";
|
|
6
|
+
export { getUkeire } from "./features/machi";
|
|
7
|
+
export { detectYaku } from "./features/yaku";
|
|
8
|
+
export { parseMspz, parseExtendedMspz } from "./features/parser";
|
|
9
|
+
export { calculateScore } from "./features/points";
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 牌種IDの定数セット
|
|
3
|
+
*
|
|
4
|
+
* - 0-8: 萬子 (ManZu)
|
|
5
|
+
* - 9-17: 筒子 (PinZu)
|
|
6
|
+
* - 18-26: 索子 (SouZu)
|
|
7
|
+
* - 27-33: 字牌 (JiHai)
|
|
8
|
+
*/
|
|
9
|
+
export declare const HAI_KIND_IDS: readonly [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33];
|
|
10
|
+
type TupleOf<T, N extends number, R extends unknown[] = []> = R["length"] extends N ? R : TupleOf<T, N, [T, ...R]>;
|
|
11
|
+
/**
|
|
12
|
+
* 牌の種類の総数 (34)
|
|
13
|
+
*/
|
|
14
|
+
export type HaiKindCount = (typeof HAI_KIND_IDS)["length"];
|
|
15
|
+
/**
|
|
16
|
+
* 特定の種類の牌の所持数 (0-4枚)
|
|
17
|
+
* 各種類の牌は最大4枚まで存在します。
|
|
18
|
+
*/
|
|
19
|
+
export type HaiQuantity = 0 | 1 | 2 | 3 | 4;
|
|
20
|
+
/**
|
|
21
|
+
* 全34種類の牌の所持数分布配列。
|
|
22
|
+
* インデックスは HaiKindId (0-33) に対応します。
|
|
23
|
+
* 各要素はその種類の牌の所持数 (0-4) です。
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // "113m 1z" (MPSZ形式) に対応
|
|
27
|
+
* const dist: HaiKindDistribution = [
|
|
28
|
+
* 2, 0, 1, 0, 0, 0, 0, 0, 0, // 萬子 (1m x2, 3m x1)
|
|
29
|
+
* 0, 0, 0, 0, 0, 0, 0, 0, 0, // 筒子
|
|
30
|
+
* 0, 0, 0, 0, 0, 0, 0, 0, 0, // 索子
|
|
31
|
+
* 1, 0, 0, 0, 0, 0, 0 // 字牌 (1z x1)
|
|
32
|
+
* ];
|
|
33
|
+
*/
|
|
34
|
+
export type HaiKindDistribution = Readonly<TupleOf<HaiQuantity, HaiKindCount>>;
|
|
35
|
+
/**
|
|
36
|
+
* 物理的な牌の一意な識別子 (HaiId)
|
|
37
|
+
*
|
|
38
|
+
* 麻雀セットに含まれる136枚の牌それぞれに一意のIDが割り当てられます (0-135)。
|
|
39
|
+
*
|
|
40
|
+
* - 0-35: 萬子
|
|
41
|
+
* - 36-71: 筒子
|
|
42
|
+
* - 72-107: 索子
|
|
43
|
+
* - 108-135: 字牌
|
|
44
|
+
*
|
|
45
|
+
* Branded Type を使用して通常の number と区別します。
|
|
46
|
+
*/
|
|
47
|
+
export type HaiId = number & {
|
|
48
|
+
readonly __brand: "HaiId";
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* 牌種ID (HaiKindId)
|
|
52
|
+
*
|
|
53
|
+
* 麻雀の34種類の牌を一意に識別するID。
|
|
54
|
+
*/
|
|
55
|
+
export type HaiKindId = (typeof HAI_KIND_IDS)[number];
|
|
56
|
+
/**
|
|
57
|
+
* 牌種 (HaiKind)
|
|
58
|
+
*
|
|
59
|
+
* 牌種IDに対応する定数定義。
|
|
60
|
+
*/
|
|
61
|
+
export declare const HaiKind: {
|
|
62
|
+
readonly ManZu1: 0;
|
|
63
|
+
readonly ManZu2: 1;
|
|
64
|
+
readonly ManZu3: 2;
|
|
65
|
+
readonly ManZu4: 3;
|
|
66
|
+
readonly ManZu5: 4;
|
|
67
|
+
readonly ManZu6: 5;
|
|
68
|
+
readonly ManZu7: 6;
|
|
69
|
+
readonly ManZu8: 7;
|
|
70
|
+
readonly ManZu9: 8;
|
|
71
|
+
readonly PinZu1: 9;
|
|
72
|
+
readonly PinZu2: 10;
|
|
73
|
+
readonly PinZu3: 11;
|
|
74
|
+
readonly PinZu4: 12;
|
|
75
|
+
readonly PinZu5: 13;
|
|
76
|
+
readonly PinZu6: 14;
|
|
77
|
+
readonly PinZu7: 15;
|
|
78
|
+
readonly PinZu8: 16;
|
|
79
|
+
readonly PinZu9: 17;
|
|
80
|
+
readonly SouZu1: 18;
|
|
81
|
+
readonly SouZu2: 19;
|
|
82
|
+
readonly SouZu3: 20;
|
|
83
|
+
readonly SouZu4: 21;
|
|
84
|
+
readonly SouZu5: 22;
|
|
85
|
+
readonly SouZu6: 23;
|
|
86
|
+
readonly SouZu7: 24;
|
|
87
|
+
readonly SouZu8: 25;
|
|
88
|
+
readonly SouZu9: 26;
|
|
89
|
+
readonly Ton: 27;
|
|
90
|
+
readonly Nan: 28;
|
|
91
|
+
readonly Sha: 29;
|
|
92
|
+
readonly Pei: 30;
|
|
93
|
+
readonly Haku: 31;
|
|
94
|
+
readonly Hatsu: 32;
|
|
95
|
+
readonly Chun: 33;
|
|
96
|
+
};
|
|
97
|
+
export type HaiKind = (typeof HaiKind)[keyof typeof HaiKind];
|
|
98
|
+
/**
|
|
99
|
+
* 牌種タイプ (HaiType)
|
|
100
|
+
*/
|
|
101
|
+
export declare const HaiType: {
|
|
102
|
+
readonly Manzu: "Manzu";
|
|
103
|
+
readonly Pinzu: "Pinzu";
|
|
104
|
+
readonly Souzu: "Souzu";
|
|
105
|
+
readonly Jihai: "Jihai";
|
|
106
|
+
};
|
|
107
|
+
export type HaiType = (typeof HaiType)[keyof typeof HaiType];
|
|
108
|
+
export type Suupai = typeof HaiType.Manzu | typeof HaiType.Pinzu | typeof HaiType.Souzu;
|
|
109
|
+
export type Jihai = typeof HaiType.Jihai;
|
|
110
|
+
/**
|
|
111
|
+
* シャンテン数 (ShantenNumber)
|
|
112
|
+
*
|
|
113
|
+
* 和了までの手数 - 1 を表す数値。
|
|
114
|
+
*
|
|
115
|
+
* - 0: テンパイ (Tenpai) - 次の1手で和了できる状態
|
|
116
|
+
* - 1: 1シャンテン - テンパイまであと1手
|
|
117
|
+
* - ...
|
|
118
|
+
* - 13: 理論上の最大値 (例: 13面待ちでない国士無双の初期状態など)
|
|
119
|
+
*
|
|
120
|
+
* ※ 本ライブラリでは、ツモる前の13枚の手牌に対する計算を前提とするため、
|
|
121
|
+
* 和了 (-1) はこの型には含めない。
|
|
122
|
+
*/
|
|
123
|
+
export type ShantenNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
|
|
124
|
+
/**
|
|
125
|
+
* 他家 (Tacha)
|
|
126
|
+
*
|
|
127
|
+
* 自分から見た他家の位置関係(相対席)。
|
|
128
|
+
* 副露(鳴き)の発生元などを表現するために使用する。
|
|
129
|
+
*
|
|
130
|
+
* - 1: 下家 (Shimocha) - 右側
|
|
131
|
+
* - 2: 対面 (Toimen) - 正面
|
|
132
|
+
* - 3: 上家 (Kamicha) - 左側
|
|
133
|
+
*/
|
|
134
|
+
export declare const Tacha: {
|
|
135
|
+
readonly Shimocha: 1;
|
|
136
|
+
readonly Toimen: 2;
|
|
137
|
+
readonly Kamicha: 3;
|
|
138
|
+
};
|
|
139
|
+
export type Tacha = (typeof Tacha)[keyof typeof Tacha];
|
|
140
|
+
/**
|
|
141
|
+
* 副露種別 (FuroType)
|
|
142
|
+
*/
|
|
143
|
+
export declare const FuroType: {
|
|
144
|
+
readonly Chi: "Chi";
|
|
145
|
+
readonly Pon: "Pon";
|
|
146
|
+
readonly Daiminkan: "Daiminkan";
|
|
147
|
+
readonly Kakan: "Kakan";
|
|
148
|
+
};
|
|
149
|
+
export type FuroType = (typeof FuroType)[keyof typeof FuroType];
|
|
150
|
+
/**
|
|
151
|
+
* 副露 (Furo)
|
|
152
|
+
*
|
|
153
|
+
* 面子に対する「鳴き」のメタ情報。
|
|
154
|
+
* ここでは副露を「自分の手牌が不足している面子を、他家が捨てた牌を取って完成させる行為」と定義し、
|
|
155
|
+
* 暗槓(自力で4枚揃える行為)はここには含めない。
|
|
156
|
+
*
|
|
157
|
+
* 構成する牌自体はここには含めず、この型を持つ親(Mentsuなど)が保持することを想定する。
|
|
158
|
+
*/
|
|
159
|
+
export type Furo = {
|
|
160
|
+
readonly type: typeof FuroType.Chi;
|
|
161
|
+
readonly from: Tacha;
|
|
162
|
+
} | {
|
|
163
|
+
readonly type: typeof FuroType.Pon;
|
|
164
|
+
readonly from: Tacha;
|
|
165
|
+
} | {
|
|
166
|
+
readonly type: typeof FuroType.Daiminkan;
|
|
167
|
+
readonly from: Tacha;
|
|
168
|
+
} | {
|
|
169
|
+
readonly type: typeof FuroType.Kakan;
|
|
170
|
+
readonly from: Tacha;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* 面子種別 (MentsuType)
|
|
174
|
+
*/
|
|
175
|
+
export declare const MentsuType: {
|
|
176
|
+
readonly Shuntsu: "Shuntsu";
|
|
177
|
+
readonly Koutsu: "Koutsu";
|
|
178
|
+
readonly Kantsu: "Kantsu";
|
|
179
|
+
readonly Toitsu: "Toitsu";
|
|
180
|
+
readonly Tatsu: "Tatsu";
|
|
181
|
+
};
|
|
182
|
+
export type MentsuType = (typeof MentsuType)[keyof typeof MentsuType];
|
|
183
|
+
/**
|
|
184
|
+
* 基本的な面子構造 (ジェネリック)
|
|
185
|
+
*
|
|
186
|
+
* 牌の型をジェネリクス `T` で抽象化することで、以下の両方のユースケースに対応します:
|
|
187
|
+
* 1. `HaiKindId`: MPSZ形式の手牌をもとにシャンテン計算を行うなど、牌の種類のみに関心がある場合(抽象的な計算)。
|
|
188
|
+
* 2. `HaiId`: 実際のゲームの牌譜など、牌の物理的なIDを処理対象とする場合(具象的な計算)。
|
|
189
|
+
*/
|
|
190
|
+
interface BaseMentsu<T extends HaiKindId | HaiId> {
|
|
191
|
+
readonly type: MentsuType;
|
|
192
|
+
/**
|
|
193
|
+
* 構成する牌のリスト。
|
|
194
|
+
*
|
|
195
|
+
* 各面子型(Shuntsu等)において固定長タプル(例: `[T, T, T]`)として再定義することで、
|
|
196
|
+
* 面子の種類ごとの正しい牌枚数(順子なら3枚、槓子なら4枚など)を型レベルで強制します。
|
|
197
|
+
*/
|
|
198
|
+
hais: readonly T[];
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* 順子 (Shuntsu)
|
|
202
|
+
*/
|
|
203
|
+
export type Shuntsu<T extends HaiKindId | HaiId = HaiKindId> = BaseMentsu<T> & {
|
|
204
|
+
readonly type: typeof MentsuType.Shuntsu;
|
|
205
|
+
readonly hais: readonly [T, T, T];
|
|
206
|
+
readonly furo?: Furo;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* 刻子 (Koutsu)
|
|
210
|
+
*/
|
|
211
|
+
export type Koutsu<T extends HaiKindId | HaiId = HaiKindId> = BaseMentsu<T> & {
|
|
212
|
+
readonly type: typeof MentsuType.Koutsu;
|
|
213
|
+
readonly hais: readonly [T, T, T];
|
|
214
|
+
readonly furo?: Furo;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* 槓子 (Kantsu)
|
|
218
|
+
*/
|
|
219
|
+
export type Kantsu<T extends HaiKindId | HaiId = HaiKindId> = BaseMentsu<T> & {
|
|
220
|
+
readonly type: typeof MentsuType.Kantsu;
|
|
221
|
+
readonly hais: readonly [T, T, T, T];
|
|
222
|
+
readonly furo?: Furo;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* 対子 (Toitsu)
|
|
226
|
+
*/
|
|
227
|
+
export type Toitsu<T extends HaiKindId | HaiId = HaiKindId> = BaseMentsu<T> & {
|
|
228
|
+
readonly type: typeof MentsuType.Toitsu;
|
|
229
|
+
readonly hais: readonly [T, T];
|
|
230
|
+
readonly furo?: never;
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* 塔子 (Tatsu)
|
|
234
|
+
*/
|
|
235
|
+
export type Tatsu<T extends HaiKindId | HaiId = HaiKindId> = BaseMentsu<T> & {
|
|
236
|
+
readonly type: typeof MentsuType.Tatsu;
|
|
237
|
+
readonly hais: readonly [T, T];
|
|
238
|
+
readonly furo?: never;
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* 完成面子 (CompletedMentsu)
|
|
242
|
+
* - 順子 (Shuntsu)
|
|
243
|
+
* - 刻子 (Koutsu)
|
|
244
|
+
* - 槓子 (Kantsu)
|
|
245
|
+
*/
|
|
246
|
+
export type CompletedMentsu<T extends HaiKindId | HaiId = HaiKindId> = Shuntsu<T> | Koutsu<T> | Kantsu<T>;
|
|
247
|
+
/**
|
|
248
|
+
* 未完成面子 (IncompletedMentsu)
|
|
249
|
+
* - 対子 (Toitsu)
|
|
250
|
+
* - 塔子 (Tatsu)
|
|
251
|
+
*/
|
|
252
|
+
export type IncompletedMentsu<T extends HaiKindId | HaiId = HaiKindId> = Toitsu<T> | Tatsu<T>;
|
|
253
|
+
/**
|
|
254
|
+
* 面子 (Mentsu)
|
|
255
|
+
*
|
|
256
|
+
* 広義の面子(ブロック)。指定がない場合は HaiKindId のリストを持つ。
|
|
257
|
+
*/
|
|
258
|
+
export type Mentsu<T extends HaiKindId | HaiId = HaiKindId> = CompletedMentsu<T> | IncompletedMentsu<T>;
|
|
259
|
+
/** 自風・場風を表す牌 (東・南・西・北) */
|
|
260
|
+
export type Kazehai = typeof HaiKind.Ton | typeof HaiKind.Nan | typeof HaiKind.Sha | typeof HaiKind.Pei;
|
|
261
|
+
export type HaiIsYaocyu<ID extends HaiKindId | HaiId> = ID extends 0 | 8 | 9 ? true : false;
|
|
262
|
+
/**
|
|
263
|
+
* 手牌 (Tehai)
|
|
264
|
+
*
|
|
265
|
+
* 純手牌と副露を合わせたもの。
|
|
266
|
+
* @template T 牌の型 (HaiKindId | HaiId)
|
|
267
|
+
*/
|
|
268
|
+
export interface Tehai<T extends HaiKindId | HaiId = HaiKindId> {
|
|
269
|
+
readonly closed: readonly T[];
|
|
270
|
+
readonly exposed: readonly CompletedMentsu<T>[];
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* ツモる前の手牌 (13枚)
|
|
274
|
+
*/
|
|
275
|
+
export type Tehai13<T extends HaiKindId | HaiId = HaiKindId> = Tehai<T>;
|
|
276
|
+
/**
|
|
277
|
+
* ツモった後の手牌 (14枚)
|
|
278
|
+
*/
|
|
279
|
+
export type Tehai14<T extends HaiKindId | HaiId = HaiKindId> = Tehai<T>;
|
|
280
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 牌種IDの定数セット
|
|
3
|
+
*
|
|
4
|
+
* - 0-8: 萬子 (ManZu)
|
|
5
|
+
* - 9-17: 筒子 (PinZu)
|
|
6
|
+
* - 18-26: 索子 (SouZu)
|
|
7
|
+
* - 27-33: 字牌 (JiHai)
|
|
8
|
+
*/
|
|
9
|
+
export const HAI_KIND_IDS = [
|
|
10
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
|
|
11
|
+
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* 牌種 (HaiKind)
|
|
15
|
+
*
|
|
16
|
+
* 牌種IDに対応する定数定義。
|
|
17
|
+
*/
|
|
18
|
+
export const HaiKind = {
|
|
19
|
+
ManZu1: 0,
|
|
20
|
+
ManZu2: 1,
|
|
21
|
+
ManZu3: 2,
|
|
22
|
+
ManZu4: 3,
|
|
23
|
+
ManZu5: 4,
|
|
24
|
+
ManZu6: 5,
|
|
25
|
+
ManZu7: 6,
|
|
26
|
+
ManZu8: 7,
|
|
27
|
+
ManZu9: 8,
|
|
28
|
+
PinZu1: 9,
|
|
29
|
+
PinZu2: 10,
|
|
30
|
+
PinZu3: 11,
|
|
31
|
+
PinZu4: 12,
|
|
32
|
+
PinZu5: 13,
|
|
33
|
+
PinZu6: 14,
|
|
34
|
+
PinZu7: 15,
|
|
35
|
+
PinZu8: 16,
|
|
36
|
+
PinZu9: 17,
|
|
37
|
+
SouZu1: 18,
|
|
38
|
+
SouZu2: 19,
|
|
39
|
+
SouZu3: 20,
|
|
40
|
+
SouZu4: 21,
|
|
41
|
+
SouZu5: 22,
|
|
42
|
+
SouZu6: 23,
|
|
43
|
+
SouZu7: 24,
|
|
44
|
+
SouZu8: 25,
|
|
45
|
+
SouZu9: 26,
|
|
46
|
+
Ton: 27,
|
|
47
|
+
Nan: 28,
|
|
48
|
+
Sha: 29,
|
|
49
|
+
Pei: 30,
|
|
50
|
+
Haku: 31,
|
|
51
|
+
Hatsu: 32,
|
|
52
|
+
Chun: 33,
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* 牌種タイプ (HaiType)
|
|
56
|
+
*/
|
|
57
|
+
export const HaiType = {
|
|
58
|
+
Manzu: "Manzu",
|
|
59
|
+
Pinzu: "Pinzu",
|
|
60
|
+
Souzu: "Souzu",
|
|
61
|
+
Jihai: "Jihai",
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* 他家 (Tacha)
|
|
65
|
+
*
|
|
66
|
+
* 自分から見た他家の位置関係(相対席)。
|
|
67
|
+
* 副露(鳴き)の発生元などを表現するために使用する。
|
|
68
|
+
*
|
|
69
|
+
* - 1: 下家 (Shimocha) - 右側
|
|
70
|
+
* - 2: 対面 (Toimen) - 正面
|
|
71
|
+
* - 3: 上家 (Kamicha) - 左側
|
|
72
|
+
*/
|
|
73
|
+
export const Tacha = {
|
|
74
|
+
Shimocha: 1,
|
|
75
|
+
Toimen: 2,
|
|
76
|
+
Kamicha: 3,
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* 副露種別 (FuroType)
|
|
80
|
+
*/
|
|
81
|
+
export const FuroType = {
|
|
82
|
+
Chi: "Chi",
|
|
83
|
+
Pon: "Pon",
|
|
84
|
+
Daiminkan: "Daiminkan",
|
|
85
|
+
Kakan: "Kakan",
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* 面子種別 (MentsuType)
|
|
89
|
+
*/
|
|
90
|
+
export const MentsuType = {
|
|
91
|
+
Shuntsu: "Shuntsu", // 順子 (123)
|
|
92
|
+
Koutsu: "Koutsu", // 刻子 (111)
|
|
93
|
+
Kantsu: "Kantsu", // 槓子 (1111)
|
|
94
|
+
Toitsu: "Toitsu", // 対子 (11)
|
|
95
|
+
Tatsu: "Tatsu", // 塔子 (12, 13)
|
|
96
|
+
};
|
|
97
|
+
// ... types existing ...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type HaiId, type HaiKindId } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if the array has exactly 2 elements and narrows the type to a tuple.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isTuple2<T>(arr: readonly T[]): arr is readonly [T, T];
|
|
6
|
+
/**
|
|
7
|
+
* Checks if the array has exactly 3 elements and narrows the type to a tuple.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isTuple3<T>(arr: readonly T[]): arr is readonly [T, T, T];
|
|
10
|
+
/**
|
|
11
|
+
* Checks if the array has exactly 4 elements and narrows the type to a tuple.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isTuple4<T>(arr: readonly T[]): arr is readonly [T, T, T, T];
|
|
14
|
+
/**
|
|
15
|
+
* Casts a number to HaiKindId safely (conceptually).
|
|
16
|
+
* Use this only when you are sure the number is a valid HaiKindId.
|
|
17
|
+
*/
|
|
18
|
+
export declare function asHaiKindId(id: number): HaiKindId;
|
|
19
|
+
/**
|
|
20
|
+
* Casts a number to HaiId safely (conceptually).
|
|
21
|
+
*/
|
|
22
|
+
export declare function asHaiId(id: number): HaiId;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the array has exactly 2 elements and narrows the type to a tuple.
|
|
3
|
+
*/
|
|
4
|
+
export function isTuple2(arr) {
|
|
5
|
+
return arr.length === 2;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Checks if the array has exactly 3 elements and narrows the type to a tuple.
|
|
9
|
+
*/
|
|
10
|
+
export function isTuple3(arr) {
|
|
11
|
+
return arr.length === 3;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Checks if the array has exactly 4 elements and narrows the type to a tuple.
|
|
15
|
+
*/
|
|
16
|
+
export function isTuple4(arr) {
|
|
17
|
+
return arr.length === 4;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Casts a number to HaiKindId safely (conceptually).
|
|
21
|
+
* Use this only when you are sure the number is a valid HaiKindId.
|
|
22
|
+
*/
|
|
23
|
+
export function asHaiKindId(id) {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Casts a number to HaiId safely (conceptually).
|
|
29
|
+
*/
|
|
30
|
+
export function asHaiId(id) {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { HaiId, HaiKindId, Tehai13, Tehai14, Mentsu, MentsuType } from "../types";
|
|
2
|
+
import type { Shuntsu, Koutsu, Toitsu, CompletedMentsu } from "../types";
|
|
3
|
+
import type { HouraStructure } from "../features/yaku/types";
|
|
4
|
+
/**
|
|
5
|
+
* テスト用の Tehai13 オブジェクトを作成します。
|
|
6
|
+
* 作成時に validateTehai13 を実行し、不正な場合はエラーをスローします。
|
|
7
|
+
* これにより、テストデータが正しい Tehai13 であることを保証します。
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTehai13<T extends HaiKindId | HaiId>(closed: readonly T[]): Tehai13<T>;
|
|
10
|
+
/**
|
|
11
|
+
* テスト用の Mentsu オブジェクトを作成します。
|
|
12
|
+
*/
|
|
13
|
+
export declare function createMentsu<T extends HaiKindId | HaiId>(type: MentsuType, hais: readonly T[]): Mentsu<T>;
|
|
14
|
+
/**
|
|
15
|
+
* テスト用の Tehai14 (和了手など) オブジェクトを作成します。
|
|
16
|
+
* Extended MSPZ形式の文字列をサポートし、副露や暗槓を含む手牌を簡単に作成できます。
|
|
17
|
+
*
|
|
18
|
+
* @param mspzString Extended MSPZ形式、または通常のMSPZ形式の文字列
|
|
19
|
+
* @returns Tehai14 オブジェクト
|
|
20
|
+
*/
|
|
21
|
+
export declare function createTehai(mspzString: string): Tehai14;
|
|
22
|
+
/**
|
|
23
|
+
* MSPZ形式の文字列から HaiKindId の配列を作成します。
|
|
24
|
+
* テストデータの期待値作成などで使用します。
|
|
25
|
+
*
|
|
26
|
+
* @param mspzString MSPZ形式の文字列 (例: "123m")
|
|
27
|
+
* @returns HaiKindId の配列
|
|
28
|
+
*/
|
|
29
|
+
export declare function createHaiKindIds(mspzString: string): HaiKindId[];
|
|
30
|
+
/**
|
|
31
|
+
* テスト用の順子 (Shuntsu) を作成します。
|
|
32
|
+
* isValidShuntsu によるバリデーションを行います。
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* テスト用の順子 (Shuntsu) を作成します。
|
|
36
|
+
* isValidShuntsu によるバリデーションを行います。
|
|
37
|
+
*/
|
|
38
|
+
export declare function createShuntsu(mspz: string): Shuntsu;
|
|
39
|
+
/**
|
|
40
|
+
* テスト用の刻子 (Koutsu) を作成します。
|
|
41
|
+
*/
|
|
42
|
+
export declare function createKoutsu(mspz: string): Koutsu;
|
|
43
|
+
/**
|
|
44
|
+
* テスト用の対子 (Toitsu) を作成します。
|
|
45
|
+
*/
|
|
46
|
+
export declare function createToitsu(mspz: string): Toitsu;
|
|
47
|
+
/**
|
|
48
|
+
* テスト用の HaiKindId を取得します。
|
|
49
|
+
*/
|
|
50
|
+
export declare function getHaiKindId(mspz: string): HaiKindId;
|
|
51
|
+
/**
|
|
52
|
+
* テスト用のモック手牌 (HouraStructure) を作成します。
|
|
53
|
+
* 指定された面子と雀頭を使用し、残りはダミーの順子で埋めます。
|
|
54
|
+
*/
|
|
55
|
+
export declare function createMockHand(targetMentsu: CompletedMentsu, jantou: Toitsu): HouraStructure;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { validateTehai13 } from "../core/tehai";
|
|
2
|
+
import { isExtendedMspz, parseExtendedMspz, parseMspz, } from "../features/parser";
|
|
3
|
+
import { isValidShuntsu } from "../core/mentsu";
|
|
4
|
+
import { isTuple2, isTuple3 } from "./assertions";
|
|
5
|
+
/**
|
|
6
|
+
* テスト用の Tehai13 オブジェクトを作成します。
|
|
7
|
+
* 作成時に validateTehai13 を実行し、不正な場合はエラーをスローします。
|
|
8
|
+
* これにより、テストデータが正しい Tehai13 であることを保証します。
|
|
9
|
+
*/
|
|
10
|
+
export function createTehai13(closed) {
|
|
11
|
+
const tehai = {
|
|
12
|
+
closed,
|
|
13
|
+
exposed: [],
|
|
14
|
+
};
|
|
15
|
+
validateTehai13(tehai);
|
|
16
|
+
return tehai;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* テスト用の Mentsu オブジェクトを作成します。
|
|
20
|
+
*/
|
|
21
|
+
export function createMentsu(type, hais) {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
23
|
+
return { type, hais };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* テスト用の Tehai14 (和了手など) オブジェクトを作成します。
|
|
27
|
+
* Extended MSPZ形式の文字列をサポートし、副露や暗槓を含む手牌を簡単に作成できます。
|
|
28
|
+
*
|
|
29
|
+
* @param mspzString Extended MSPZ形式、または通常のMSPZ形式の文字列
|
|
30
|
+
* @returns Tehai14 オブジェクト
|
|
31
|
+
*/
|
|
32
|
+
export function createTehai(mspzString) {
|
|
33
|
+
if (isExtendedMspz(mspzString)) {
|
|
34
|
+
return parseExtendedMspz(mspzString);
|
|
35
|
+
}
|
|
36
|
+
// 通常のMSPZ形式の場合
|
|
37
|
+
return parseMspz(mspzString);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* MSPZ形式の文字列から HaiKindId の配列を作成します。
|
|
41
|
+
* テストデータの期待値作成などで使用します。
|
|
42
|
+
*
|
|
43
|
+
* @param mspzString MSPZ形式の文字列 (例: "123m")
|
|
44
|
+
* @returns HaiKindId の配列
|
|
45
|
+
*/
|
|
46
|
+
export function createHaiKindIds(mspzString) {
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
48
|
+
return parseMspz(mspzString).closed;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* テスト用の順子 (Shuntsu) を作成します。
|
|
52
|
+
* isValidShuntsu によるバリデーションを行います。
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* テスト用の順子 (Shuntsu) を作成します。
|
|
56
|
+
* isValidShuntsu によるバリデーションを行います。
|
|
57
|
+
*/
|
|
58
|
+
export function createShuntsu(mspz) {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
60
|
+
const ids = parseMspz(mspz).closed;
|
|
61
|
+
// Use core validation
|
|
62
|
+
if (!isValidShuntsu(ids)) {
|
|
63
|
+
throw new Error(`Invalid Shuntsu: ${mspz}`);
|
|
64
|
+
}
|
|
65
|
+
// isValidShuntsu ensures it is a valid Tuple3 of HaiKindId
|
|
66
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
67
|
+
const validIds = ids;
|
|
68
|
+
return {
|
|
69
|
+
type: "Shuntsu",
|
|
70
|
+
hais: validIds,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* テスト用の刻子 (Koutsu) を作成します。
|
|
75
|
+
*/
|
|
76
|
+
export function createKoutsu(mspz) {
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
78
|
+
const ids = parseMspz(mspz).closed;
|
|
79
|
+
if (!isTuple3(ids))
|
|
80
|
+
throw new Error(`Invalid Koutsu: ${mspz}`);
|
|
81
|
+
return {
|
|
82
|
+
type: "Koutsu",
|
|
83
|
+
hais: ids,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* テスト用の対子 (Toitsu) を作成します。
|
|
88
|
+
*/
|
|
89
|
+
export function createToitsu(mspz) {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
91
|
+
const ids = parseMspz(mspz).closed;
|
|
92
|
+
if (!isTuple2(ids))
|
|
93
|
+
throw new Error(`Invalid Toitsu: ${mspz}`);
|
|
94
|
+
return {
|
|
95
|
+
type: "Toitsu",
|
|
96
|
+
hais: ids,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* テスト用の HaiKindId を取得します。
|
|
101
|
+
*/
|
|
102
|
+
export function getHaiKindId(mspz) {
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
104
|
+
const ids = parseMspz(mspz).closed;
|
|
105
|
+
if (ids.length === 0)
|
|
106
|
+
throw new Error(`Invalid HaiKindId: ${mspz}`);
|
|
107
|
+
const id = ids[0];
|
|
108
|
+
if (id === undefined)
|
|
109
|
+
throw new Error(`Internal Error: id is undefined`);
|
|
110
|
+
return id;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* テスト用のモック手牌 (HouraStructure) を作成します。
|
|
114
|
+
* 指定された面子と雀頭を使用し、残りはダミーの順子で埋めます。
|
|
115
|
+
*/
|
|
116
|
+
export function createMockHand(targetMentsu, jantou) {
|
|
117
|
+
// Fill rest with dummy
|
|
118
|
+
const dummyShuntsu = createShuntsu("123s");
|
|
119
|
+
return {
|
|
120
|
+
type: "Mentsu",
|
|
121
|
+
fourMentsu: [targetMentsu, dummyShuntsu, dummyShuntsu, dummyShuntsu],
|
|
122
|
+
jantou,
|
|
123
|
+
};
|
|
124
|
+
}
|