@pai-forge/riichi-mahjong 0.1.0 → 0.2.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 +3 -0
- package/package.json +1 -1
- package/dist/core/dora.d.ts +0 -14
- package/dist/core/dora.js +0 -71
- package/dist/core/hai.d.ts +0 -30
- package/dist/core/hai.js +0 -78
- package/dist/core/machi.d.ts +0 -11
- package/dist/core/machi.js +0 -58
- package/dist/core/mentsu.d.ts +0 -26
- package/dist/core/mentsu.js +0 -87
- package/dist/core/tehai.d.ts +0 -38
- package/dist/core/tehai.js +0 -87
- package/dist/errors.d.ts +0 -40
- package/dist/errors.js +0 -58
- package/dist/features/machi/index.d.ts +0 -9
- package/dist/features/machi/index.js +0 -37
- package/dist/features/machi/types.d.ts +0 -1
- package/dist/features/machi/types.js +0 -1
- package/dist/features/parser/index.d.ts +0 -19
- package/dist/features/parser/index.js +0 -28
- package/dist/features/parser/mspz.d.ts +0 -85
- package/dist/features/parser/mspz.js +0 -365
- package/dist/features/points/constants.d.ts +0 -27
- package/dist/features/points/constants.js +0 -30
- package/dist/features/points/index.d.ts +0 -21
- package/dist/features/points/index.js +0 -174
- package/dist/features/points/lib/fu/constants.d.ts +0 -37
- package/dist/features/points/lib/fu/constants.js +0 -45
- package/dist/features/points/lib/fu/index.d.ts +0 -11
- package/dist/features/points/lib/fu/index.js +0 -23
- package/dist/features/points/lib/fu/lib/chiitoitsu.d.ts +0 -5
- package/dist/features/points/lib/fu/lib/chiitoitsu.js +0 -17
- package/dist/features/points/lib/fu/lib/kokushi.d.ts +0 -6
- package/dist/features/points/lib/fu/lib/kokushi.js +0 -18
- package/dist/features/points/lib/fu/lib/mentsu.d.ts +0 -11
- package/dist/features/points/lib/fu/lib/mentsu.js +0 -122
- package/dist/features/points/lib/fu/types.d.ts +0 -55
- package/dist/features/points/lib/fu/types.js +0 -1
- package/dist/features/points/types.d.ts +0 -27
- package/dist/features/points/types.js +0 -1
- package/dist/features/shanten/index.d.ts +0 -16
- package/dist/features/shanten/index.js +0 -25
- package/dist/features/shanten/logic/chiitoitsu.d.ts +0 -8
- package/dist/features/shanten/logic/chiitoitsu.js +0 -36
- package/dist/features/shanten/logic/kokushi.d.ts +0 -16
- package/dist/features/shanten/logic/kokushi.js +0 -48
- package/dist/features/shanten/logic/mentsu-te.d.ts +0 -8
- package/dist/features/shanten/logic/mentsu-te.js +0 -129
- package/dist/features/yaku/factory.d.ts +0 -13
- package/dist/features/yaku/factory.js +0 -19
- package/dist/features/yaku/index.d.ts +0 -12
- package/dist/features/yaku/index.js +0 -62
- package/dist/features/yaku/lib/definitions/chiitoitsu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/chiitoitsu.js +0 -12
- package/dist/features/yaku/lib/definitions/chinitsu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/chinitsu.js +0 -40
- package/dist/features/yaku/lib/definitions/chinroutou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/chinroutou.js +0 -21
- package/dist/features/yaku/lib/definitions/chuuren-poutou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/chuuren-poutou.js +0 -69
- package/dist/features/yaku/lib/definitions/daisangen.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/daisangen.js +0 -26
- package/dist/features/yaku/lib/definitions/daisuushii.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/daisuushii.js +0 -32
- package/dist/features/yaku/lib/definitions/honchan.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/honchan.js +0 -29
- package/dist/features/yaku/lib/definitions/honitsu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/honitsu.js +0 -40
- package/dist/features/yaku/lib/definitions/honroutou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/honroutou.js +0 -33
- package/dist/features/yaku/lib/definitions/iipeiko.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/iipeiko.js +0 -46
- package/dist/features/yaku/lib/definitions/ikkitsuukan.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/ikkitsuukan.js +0 -56
- package/dist/features/yaku/lib/definitions/index.d.ts +0 -30
- package/dist/features/yaku/lib/definitions/index.js +0 -90
- package/dist/features/yaku/lib/definitions/junchan.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/junchan.js +0 -25
- package/dist/features/yaku/lib/definitions/kokushi.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/kokushi.js +0 -12
- package/dist/features/yaku/lib/definitions/menzen-tsumo.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/menzen-tsumo.js +0 -8
- package/dist/features/yaku/lib/definitions/pinfu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/pinfu.js +0 -40
- package/dist/features/yaku/lib/definitions/ryanpeiko.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/ryanpeiko.js +0 -33
- package/dist/features/yaku/lib/definitions/ryuuiisou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/ryuuiisou.js +0 -43
- package/dist/features/yaku/lib/definitions/sanankou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/sanankou.js +0 -49
- package/dist/features/yaku/lib/definitions/sankantsu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/sankantsu.js +0 -18
- package/dist/features/yaku/lib/definitions/sanshoku-doujun.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/sanshoku-doujun.js +0 -58
- package/dist/features/yaku/lib/definitions/sanshoku-doukou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/sanshoku-doukou.js +0 -53
- package/dist/features/yaku/lib/definitions/shousangen.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/shousangen.js +0 -28
- package/dist/features/yaku/lib/definitions/shousuushii.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/shousuushii.js +0 -34
- package/dist/features/yaku/lib/definitions/suuankou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/suuankou.js +0 -63
- package/dist/features/yaku/lib/definitions/suukantsu.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/suukantsu.js +0 -18
- package/dist/features/yaku/lib/definitions/tanyao.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/tanyao.js +0 -23
- package/dist/features/yaku/lib/definitions/toitoi.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/toitoi.js +0 -16
- package/dist/features/yaku/lib/definitions/tsuuiisou.d.ts +0 -2
- package/dist/features/yaku/lib/definitions/tsuuiisou.js +0 -35
- package/dist/features/yaku/lib/definitions/yakuhai.d.ts +0 -4
- package/dist/features/yaku/lib/definitions/yakuhai.js +0 -21
- package/dist/features/yaku/lib/index.d.ts +0 -1
- package/dist/features/yaku/lib/index.js +0 -1
- package/dist/features/yaku/lib/structures/chiitoitsu.d.ts +0 -6
- package/dist/features/yaku/lib/structures/chiitoitsu.js +0 -38
- package/dist/features/yaku/lib/structures/index.d.ts +0 -10
- package/dist/features/yaku/lib/structures/index.js +0 -17
- package/dist/features/yaku/lib/structures/kokushi.d.ts +0 -6
- package/dist/features/yaku/lib/structures/kokushi.js +0 -43
- package/dist/features/yaku/lib/structures/mentsu-te.d.ts +0 -24
- package/dist/features/yaku/lib/structures/mentsu-te.js +0 -127
- package/dist/features/yaku/types.d.ts +0 -121
- package/dist/features/yaku/types.js +0 -1
- package/dist/features/yaku/utils.d.ts +0 -19
- package/dist/features/yaku/utils.js +0 -34
- package/dist/index.d.ts +0 -12
- package/dist/index.js +0 -9
- package/dist/types.d.ts +0 -280
- package/dist/types.js +0 -97
- package/dist/utils/assertions.d.ts +0 -22
- package/dist/utils/assertions.js +0 -33
- package/dist/utils/test-helpers.d.ts +0 -55
- package/dist/utils/test-helpers.js +0 -124
package/README.md
CHANGED
package/package.json
CHANGED
package/dist/core/dora.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type HaiKindId, type Tehai } from "../types";
|
|
2
|
-
/**
|
|
3
|
-
* ドラ表示牌から次の牌(ドラ)を求める
|
|
4
|
-
* @param indicator ドラ表示牌のID (HaiKindId)
|
|
5
|
-
* @returns ドラ牌のID (HaiKindId)
|
|
6
|
-
*/
|
|
7
|
-
export declare function getDoraNext(indicator: HaiKindId): HaiKindId;
|
|
8
|
-
/**
|
|
9
|
-
* 手牌に含まれるドラの数を数える
|
|
10
|
-
* @param tehai 手牌
|
|
11
|
-
* @param indicators ドラ表示牌のリスト
|
|
12
|
-
* @returns ドラの総数
|
|
13
|
-
*/
|
|
14
|
-
export declare function countDora(tehai: Tehai, indicators: readonly HaiKindId[]): number;
|
package/dist/core/dora.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { HaiKind } from "../types";
|
|
2
|
-
import { kindIdToHaiType } from "./hai";
|
|
3
|
-
import { HaiType } from "../types";
|
|
4
|
-
import { asHaiKindId } from "../utils/assertions";
|
|
5
|
-
/**
|
|
6
|
-
* ドラ表示牌から次の牌(ドラ)を求める
|
|
7
|
-
* @param indicator ドラ表示牌のID (HaiKindId)
|
|
8
|
-
* @returns ドラ牌のID (HaiKindId)
|
|
9
|
-
*/
|
|
10
|
-
export function getDoraNext(indicator) {
|
|
11
|
-
const type = kindIdToHaiType(indicator);
|
|
12
|
-
if (type === HaiType.Manzu) {
|
|
13
|
-
if (indicator === HaiKind.ManZu9)
|
|
14
|
-
return HaiKind.ManZu1;
|
|
15
|
-
return asHaiKindId(indicator + 1);
|
|
16
|
-
}
|
|
17
|
-
if (type === HaiType.Pinzu) {
|
|
18
|
-
if (indicator === HaiKind.PinZu9)
|
|
19
|
-
return HaiKind.PinZu1;
|
|
20
|
-
return asHaiKindId(indicator + 1);
|
|
21
|
-
}
|
|
22
|
-
if (type === HaiType.Souzu) {
|
|
23
|
-
if (indicator === HaiKind.SouZu9)
|
|
24
|
-
return HaiKind.SouZu1;
|
|
25
|
-
return asHaiKindId(indicator + 1);
|
|
26
|
-
}
|
|
27
|
-
// Jihai
|
|
28
|
-
// Ton(27) -> Nan(28) -> Sha(29) -> Pei(30) -> Ton(27)
|
|
29
|
-
if (indicator === HaiKind.Pei)
|
|
30
|
-
return HaiKind.Ton;
|
|
31
|
-
if (indicator >= HaiKind.Ton && indicator < HaiKind.Pei) {
|
|
32
|
-
return asHaiKindId(indicator + 1);
|
|
33
|
-
}
|
|
34
|
-
// Haku(31) -> Hatsu(32) -> Chun(33) -> Haku(31)
|
|
35
|
-
if (indicator === HaiKind.Chun)
|
|
36
|
-
return HaiKind.Haku;
|
|
37
|
-
if (indicator >= HaiKind.Haku && indicator < HaiKind.Chun) {
|
|
38
|
-
return asHaiKindId(indicator + 1);
|
|
39
|
-
}
|
|
40
|
-
// Should not happen for valid HaiKindId
|
|
41
|
-
return indicator;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* 手牌に含まれるドラの数を数える
|
|
45
|
-
* @param tehai 手牌
|
|
46
|
-
* @param indicators ドラ表示牌のリスト
|
|
47
|
-
* @returns ドラの総数
|
|
48
|
-
*/
|
|
49
|
-
export function countDora(tehai, indicators) {
|
|
50
|
-
let count = 0;
|
|
51
|
-
// Calculate actual dora hinds
|
|
52
|
-
const doraHais = indicators.map(getDoraNext);
|
|
53
|
-
// Count in closed hand
|
|
54
|
-
for (const hai of tehai.closed) {
|
|
55
|
-
for (const dora of doraHais) {
|
|
56
|
-
if (hai === dora)
|
|
57
|
-
count++;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// Count in exposed mentsu
|
|
61
|
-
for (const mentsu of tehai.exposed) {
|
|
62
|
-
for (const hai of mentsu.hais) {
|
|
63
|
-
for (const dora of doraHais) {
|
|
64
|
-
if (hai === dora)
|
|
65
|
-
count++;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// TODO: Add Akadora counting logic here
|
|
70
|
-
return count;
|
|
71
|
-
}
|
package/dist/core/hai.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type HaiId, type HaiKindId, HaiType } from "../types";
|
|
2
|
-
/**
|
|
3
|
-
* 牌種IDから牌種タイプを取得する
|
|
4
|
-
*/
|
|
5
|
-
export declare function kindIdToHaiType(kind: HaiKindId): HaiType;
|
|
6
|
-
/**
|
|
7
|
-
* 物理牌IDから牌種IDを取得する
|
|
8
|
-
* 0-35: 萬子 (36枚 = 9種 * 4枚) -> 0-8
|
|
9
|
-
* 36-71: 筒子 (36枚) -> 9-17
|
|
10
|
-
* 72-107: 索子 (36枚) -> 18-26
|
|
11
|
-
* 108-135: 字牌 (28枚 = 7種 * 4枚) -> 27-33
|
|
12
|
-
*/
|
|
13
|
-
export declare function haiIdToKindId(id: HaiId): HaiKindId;
|
|
14
|
-
/**
|
|
15
|
-
* 牌種IDから数値(1-9)を取得する
|
|
16
|
-
* 字牌の場合は undefined を返す
|
|
17
|
-
*/
|
|
18
|
-
export declare function haiKindToNumber(kind: HaiKindId): number | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* 数牌かどうかを判定する
|
|
21
|
-
*/
|
|
22
|
-
export declare function isSuupai(kind: HaiKindId): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* 么九牌(1,9,字牌)の牌種IDセット
|
|
25
|
-
*/
|
|
26
|
-
export declare const YAOCHU_KIND_IDS: readonly [0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33];
|
|
27
|
-
/**
|
|
28
|
-
* 么九牌(1,9,字牌)かどうかを判定する
|
|
29
|
-
*/
|
|
30
|
-
export declare function isYaochu(kind: HaiKindId): boolean;
|
package/dist/core/hai.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { HaiKind, HaiType } from "../types";
|
|
2
|
-
import { asHaiKindId } from "../utils/assertions";
|
|
3
|
-
/**
|
|
4
|
-
* 牌種IDから牌種タイプを取得する
|
|
5
|
-
*/
|
|
6
|
-
export function kindIdToHaiType(kind) {
|
|
7
|
-
if (kind >= HaiKind.ManZu1 && kind <= HaiKind.ManZu9) {
|
|
8
|
-
return HaiType.Manzu;
|
|
9
|
-
}
|
|
10
|
-
if (kind >= HaiKind.PinZu1 && kind <= HaiKind.PinZu9) {
|
|
11
|
-
return HaiType.Pinzu;
|
|
12
|
-
}
|
|
13
|
-
if (kind >= HaiKind.SouZu1 && kind <= HaiKind.SouZu9) {
|
|
14
|
-
return HaiType.Souzu;
|
|
15
|
-
}
|
|
16
|
-
return HaiType.Jihai;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* 物理牌IDから牌種IDを取得する
|
|
20
|
-
* 0-35: 萬子 (36枚 = 9種 * 4枚) -> 0-8
|
|
21
|
-
* 36-71: 筒子 (36枚) -> 9-17
|
|
22
|
-
* 72-107: 索子 (36枚) -> 18-26
|
|
23
|
-
* 108-135: 字牌 (28枚 = 7種 * 4枚) -> 27-33
|
|
24
|
-
*/
|
|
25
|
-
export function haiIdToKindId(id) {
|
|
26
|
-
if (id < 36)
|
|
27
|
-
return asHaiKindId(Math.floor(id / 4));
|
|
28
|
-
if (id < 72)
|
|
29
|
-
return asHaiKindId(Math.floor((id - 36) / 4) + 9);
|
|
30
|
-
if (id < 108)
|
|
31
|
-
return asHaiKindId(Math.floor((id - 72) / 4) + 18);
|
|
32
|
-
return asHaiKindId(Math.floor((id - 108) / 4) + 27);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* 牌種IDから数値(1-9)を取得する
|
|
36
|
-
* 字牌の場合は undefined を返す
|
|
37
|
-
*/
|
|
38
|
-
export function haiKindToNumber(kind) {
|
|
39
|
-
const type = kindIdToHaiType(kind);
|
|
40
|
-
if (type === HaiType.Jihai)
|
|
41
|
-
return undefined;
|
|
42
|
-
if (type === HaiType.Manzu)
|
|
43
|
-
return kind - HaiKind.ManZu1 + 1;
|
|
44
|
-
if (type === HaiType.Pinzu)
|
|
45
|
-
return kind - HaiKind.PinZu1 + 1;
|
|
46
|
-
// if (kindIdToHaiType(kind) === HaiType.Souzu)
|
|
47
|
-
return kind - HaiKind.SouZu1 + 1;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* 数牌かどうかを判定する
|
|
51
|
-
*/
|
|
52
|
-
export function isSuupai(kind) {
|
|
53
|
-
return kindIdToHaiType(kind) !== HaiType.Jihai;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* 么九牌(1,9,字牌)の牌種IDセット
|
|
57
|
-
*/
|
|
58
|
-
export const YAOCHU_KIND_IDS = [
|
|
59
|
-
HaiKind.ManZu1,
|
|
60
|
-
HaiKind.ManZu9,
|
|
61
|
-
HaiKind.PinZu1,
|
|
62
|
-
HaiKind.PinZu9,
|
|
63
|
-
HaiKind.SouZu1,
|
|
64
|
-
HaiKind.SouZu9,
|
|
65
|
-
HaiKind.Ton,
|
|
66
|
-
HaiKind.Nan,
|
|
67
|
-
HaiKind.Sha,
|
|
68
|
-
HaiKind.Pei,
|
|
69
|
-
HaiKind.Haku,
|
|
70
|
-
HaiKind.Hatsu,
|
|
71
|
-
HaiKind.Chun,
|
|
72
|
-
];
|
|
73
|
-
/**
|
|
74
|
-
* 么九牌(1,9,字牌)かどうかを判定する
|
|
75
|
-
*/
|
|
76
|
-
export function isYaochu(kind) {
|
|
77
|
-
return YAOCHU_KIND_IDS.some((k) => k === kind);
|
|
78
|
-
}
|
package/dist/core/machi.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { HaiKindId } from "../types";
|
|
2
|
-
import type { HouraStructure } from "../features/yaku/types";
|
|
3
|
-
/** 待ちの形 */
|
|
4
|
-
export type MachiType = "Tanki" | "Shanpon" | "Ryanmen" | "Kanchan" | "Penchan";
|
|
5
|
-
/**
|
|
6
|
-
* 手牌構造と和了牌から待ちの形を判定する
|
|
7
|
-
* @param hand 分解された手牌構造
|
|
8
|
-
* @param agariHai 和了牌
|
|
9
|
-
* @returns 待ちの形(判定できない、または Shanpon などの場合は undefined)
|
|
10
|
-
*/
|
|
11
|
-
export declare function classifyMachi(hand: HouraStructure, agariHai: HaiKindId): MachiType | undefined;
|
package/dist/core/machi.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 手牌構造と和了牌から待ちの形を判定する
|
|
3
|
-
* @param hand 分解された手牌構造
|
|
4
|
-
* @param agariHai 和了牌
|
|
5
|
-
* @returns 待ちの形(判定できない、または Shanpon などの場合は undefined)
|
|
6
|
-
*/
|
|
7
|
-
export function classifyMachi(hand, agariHai) {
|
|
8
|
-
if (hand.type !== "Mentsu")
|
|
9
|
-
return undefined;
|
|
10
|
-
// 1. 雀頭での和了(単騎待ち)
|
|
11
|
-
if (hand.jantou.hais.includes(agariHai)) {
|
|
12
|
-
return "Tanki";
|
|
13
|
-
}
|
|
14
|
-
// 2. 順子・刻子・槓子での和了
|
|
15
|
-
for (const mentsu of hand.fourMentsu) {
|
|
16
|
-
if (mentsu.type === "Shuntsu") {
|
|
17
|
-
const machi = classifyShuntsuWait(mentsu, agariHai);
|
|
18
|
-
if (machi)
|
|
19
|
-
return machi;
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
// 3. 刻子・槓子での和了(双碰待ち)
|
|
23
|
-
// 刻子の一部が和了牌=シャボ待ちで和了
|
|
24
|
-
if (mentsu.hais.includes(agariHai)) {
|
|
25
|
-
return "Shanpon";
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 順子における待ちの形を判定する(内部ヘルパー)
|
|
33
|
-
*/
|
|
34
|
-
function classifyShuntsuWait(shuntsu, agariHai) {
|
|
35
|
-
const { hais } = shuntsu;
|
|
36
|
-
if (!hais.includes(agariHai))
|
|
37
|
-
return undefined;
|
|
38
|
-
const [a, b, c] = hais; // 順子はソートされている前提
|
|
39
|
-
if (agariHai === a) {
|
|
40
|
-
// [Agari, b, c]
|
|
41
|
-
const valC = c % 9;
|
|
42
|
-
if (valC === 8)
|
|
43
|
-
return "Penchan";
|
|
44
|
-
return "Ryanmen";
|
|
45
|
-
}
|
|
46
|
-
if (agariHai === c) {
|
|
47
|
-
// [a, b, Agari]
|
|
48
|
-
const valA = a % 9;
|
|
49
|
-
if (valA === 0)
|
|
50
|
-
return "Penchan";
|
|
51
|
-
return "Ryanmen";
|
|
52
|
-
}
|
|
53
|
-
if (agariHai === b) {
|
|
54
|
-
// [a, Agari, c]
|
|
55
|
-
return "Kanchan";
|
|
56
|
-
}
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
package/dist/core/mentsu.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { HaiKindId } from "../types";
|
|
2
|
-
/**
|
|
3
|
-
* 順子かどうかを検証する
|
|
4
|
-
|
|
5
|
-
*/
|
|
6
|
-
export declare function isValidShuntsu(kindIds: readonly HaiKindId[]): boolean;
|
|
7
|
-
/**
|
|
8
|
-
* 刻子かどうかを検証する
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export declare function isValidKoutsu(kindIds: readonly HaiKindId[]): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* 槓子かどうかを検証する
|
|
14
|
-
|
|
15
|
-
*/
|
|
16
|
-
export declare function isValidKantsu(kindIds: readonly HaiKindId[]): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* 対子かどうかを検証する
|
|
19
|
-
|
|
20
|
-
*/
|
|
21
|
-
export declare function isValidToitsu(kindIds: readonly HaiKindId[]): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* 塔子かどうかを検証する
|
|
24
|
-
|
|
25
|
-
*/
|
|
26
|
-
export declare function isValidTatsu(kindIds: readonly HaiKindId[]): boolean;
|
package/dist/core/mentsu.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { haiKindToNumber, isSuupai, kindIdToHaiType } from "./hai";
|
|
2
|
-
import { isTuple2, isTuple3, isTuple4 } from "../utils/assertions";
|
|
3
|
-
// バリデーションロジックは「HaiKindId の配列」に対して行うものと定義する。
|
|
4
|
-
// HaiId を持つ Mentsu を検証したい場合は、呼び出し側で KindId に変換してから渡す必要がある。
|
|
5
|
-
// ただし、利便性のために `convertHaiIdToKindId` ヘルパーを export する。
|
|
6
|
-
/**
|
|
7
|
-
* 順子かどうかを検証する
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
export function isValidShuntsu(kindIds) {
|
|
11
|
-
if (!isTuple3(kindIds))
|
|
12
|
-
return false;
|
|
13
|
-
const [a, b, c] = kindIds;
|
|
14
|
-
if (!isSuupai(a) || !isSuupai(b) || !isSuupai(c))
|
|
15
|
-
return false;
|
|
16
|
-
const typeA = kindIdToHaiType(a);
|
|
17
|
-
const typeB = kindIdToHaiType(b);
|
|
18
|
-
const typeC = kindIdToHaiType(c);
|
|
19
|
-
if (typeA !== typeB || typeA !== typeC)
|
|
20
|
-
return false;
|
|
21
|
-
const numA = haiKindToNumber(a);
|
|
22
|
-
const numB = haiKindToNumber(b);
|
|
23
|
-
const numC = haiKindToNumber(c);
|
|
24
|
-
if (numA === undefined || numB === undefined || numC === undefined)
|
|
25
|
-
return false;
|
|
26
|
-
// ソートして連続性をチェック
|
|
27
|
-
const sorted = [numA, numB, numC].sort((x, y) => x - y);
|
|
28
|
-
// Safe to access since we just created it with 3 elements
|
|
29
|
-
// But strict check might complain about index access on array
|
|
30
|
-
if (!isTuple3(sorted))
|
|
31
|
-
return false; // Should be always true
|
|
32
|
-
return sorted[0] + 1 === sorted[1] && sorted[1] + 1 === sorted[2];
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* 刻子かどうかを検証する
|
|
36
|
-
|
|
37
|
-
*/
|
|
38
|
-
export function isValidKoutsu(kindIds) {
|
|
39
|
-
if (!isTuple3(kindIds))
|
|
40
|
-
return false;
|
|
41
|
-
const [a, b, c] = kindIds;
|
|
42
|
-
return a === b && b === c;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* 槓子かどうかを検証する
|
|
46
|
-
|
|
47
|
-
*/
|
|
48
|
-
export function isValidKantsu(kindIds) {
|
|
49
|
-
if (!isTuple4(kindIds))
|
|
50
|
-
return false;
|
|
51
|
-
const [a, b, c, d] = kindIds;
|
|
52
|
-
return a === b && b === c && c === d;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* 対子かどうかを検証する
|
|
56
|
-
|
|
57
|
-
*/
|
|
58
|
-
export function isValidToitsu(kindIds) {
|
|
59
|
-
if (!isTuple2(kindIds))
|
|
60
|
-
return false;
|
|
61
|
-
const [a, b] = kindIds;
|
|
62
|
-
return a === b;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* 塔子かどうかを検証する
|
|
66
|
-
|
|
67
|
-
*/
|
|
68
|
-
export function isValidTatsu(kindIds) {
|
|
69
|
-
if (!isTuple2(kindIds))
|
|
70
|
-
return false;
|
|
71
|
-
const [a, b] = kindIds;
|
|
72
|
-
// 数牌でなければならない
|
|
73
|
-
if (!isSuupai(a) || !isSuupai(b))
|
|
74
|
-
return false;
|
|
75
|
-
// 同じ種類でなければならない
|
|
76
|
-
const typeA = kindIdToHaiType(a);
|
|
77
|
-
const typeB = kindIdToHaiType(b);
|
|
78
|
-
if (typeA !== typeB)
|
|
79
|
-
return false;
|
|
80
|
-
const numA = haiKindToNumber(a);
|
|
81
|
-
const numB = haiKindToNumber(b);
|
|
82
|
-
if (numA === undefined || numB === undefined)
|
|
83
|
-
return false;
|
|
84
|
-
const diff = Math.abs(numA - numB);
|
|
85
|
-
// 差が1 (ペンチャン/リャンメン) または 2 (カンチャン) ならOK
|
|
86
|
-
return diff === 1 || diff === 2;
|
|
87
|
-
}
|
package/dist/core/tehai.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { HaiId, HaiKindDistribution, HaiKindId, Tehai, Tehai13, Tehai14 } from "../types";
|
|
2
|
-
/**
|
|
3
|
-
* 手牌の有効枚数を計算します。
|
|
4
|
-
* 副露(槓子含む)は一律3枚として計算します。
|
|
5
|
-
*/
|
|
6
|
-
export declare function calculateTehaiCount<T extends HaiKindId | HaiId>(tehai: Tehai<T>): number;
|
|
7
|
-
/**
|
|
8
|
-
* 牌種ごとの枚数をカウントします。
|
|
9
|
-
*/
|
|
10
|
-
export declare function countHaiKind(hais: readonly HaiKindId[]): HaiKindDistribution;
|
|
11
|
-
/**
|
|
12
|
-
* 手牌がTehai13(有効枚数13枚)であるか検証します。
|
|
13
|
-
* @throws {ShoushaiError} 枚数が不足している場合
|
|
14
|
-
* @throws {TahaiError} 枚数が超過している場合
|
|
15
|
-
*/
|
|
16
|
-
export declare function validateTehai13<T extends HaiKindId | HaiId>(tehai: Tehai<T>): void;
|
|
17
|
-
/**
|
|
18
|
-
* 手牌がTehai14(有効枚数14枚)であるか検証します。
|
|
19
|
-
* @throws {ShoushaiError} 枚数が不足している場合
|
|
20
|
-
* @throws {TahaiError} 枚数が超過している場合
|
|
21
|
-
*/
|
|
22
|
-
export declare function validateTehai14<T extends HaiKindId | HaiId>(tehai: Tehai<T>): void;
|
|
23
|
-
/**
|
|
24
|
-
* 手牌がTehai13またはTehai14(有効枚数が13または14枚)であるか検証します。
|
|
25
|
-
* シャンテン計算や待ち判定など、13枚/14枚の区別なく手牌として扱いたい場合に使用します。
|
|
26
|
-
*
|
|
27
|
-
* @throws {ShoushaiError} 枚数が不足している場合 (< 13)
|
|
28
|
-
* @throws {TahaiError} 枚数が超過している場合 (> 14)
|
|
29
|
-
*/
|
|
30
|
-
export declare function validateTehai<T extends HaiKindId | HaiId>(tehai: Tehai<T>): void;
|
|
31
|
-
/**
|
|
32
|
-
* Type Guard for Tehai13
|
|
33
|
-
*/
|
|
34
|
-
export declare function isTehai13<T extends HaiKindId | HaiId>(tehai: Tehai<T>): tehai is Tehai13<T>;
|
|
35
|
-
/**
|
|
36
|
-
* Type Guard for Tehai14
|
|
37
|
-
*/
|
|
38
|
-
export declare function isTehai14<T extends HaiKindId | HaiId>(tehai: Tehai<T>): tehai is Tehai14<T>;
|
package/dist/core/tehai.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { ShoushaiError, TahaiError } from "../errors";
|
|
2
|
-
/**
|
|
3
|
-
* 手牌の有効枚数を計算します。
|
|
4
|
-
* 副露(槓子含む)は一律3枚として計算します。
|
|
5
|
-
*/
|
|
6
|
-
export function calculateTehaiCount(tehai) {
|
|
7
|
-
return tehai.closed.length + tehai.exposed.length * 3;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* 牌種ごとの枚数をカウントします。
|
|
11
|
-
*/
|
|
12
|
-
export function countHaiKind(hais) {
|
|
13
|
-
const counts = Array.from({ length: 34 }, () => 0);
|
|
14
|
-
for (const hai of hais) {
|
|
15
|
-
counts[hai] = (counts[hai] ?? 0) + 1;
|
|
16
|
-
}
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
18
|
-
return counts;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* 手牌がTehai13(有効枚数13枚)であるか検証します。
|
|
22
|
-
* @throws {ShoushaiError} 枚数が不足している場合
|
|
23
|
-
* @throws {TahaiError} 枚数が超過している場合
|
|
24
|
-
*/
|
|
25
|
-
export function validateTehai13(tehai) {
|
|
26
|
-
const count = calculateTehaiCount(tehai);
|
|
27
|
-
if (count < 13) {
|
|
28
|
-
throw new ShoushaiError();
|
|
29
|
-
}
|
|
30
|
-
if (count > 13) {
|
|
31
|
-
throw new TahaiError();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* 手牌がTehai14(有効枚数14枚)であるか検証します。
|
|
36
|
-
* @throws {ShoushaiError} 枚数が不足している場合
|
|
37
|
-
* @throws {TahaiError} 枚数が超過している場合
|
|
38
|
-
*/
|
|
39
|
-
export function validateTehai14(tehai) {
|
|
40
|
-
const count = calculateTehaiCount(tehai);
|
|
41
|
-
if (count < 14) {
|
|
42
|
-
throw new ShoushaiError();
|
|
43
|
-
}
|
|
44
|
-
if (count > 14) {
|
|
45
|
-
throw new TahaiError();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* 手牌がTehai13またはTehai14(有効枚数が13または14枚)であるか検証します。
|
|
50
|
-
* シャンテン計算や待ち判定など、13枚/14枚の区別なく手牌として扱いたい場合に使用します。
|
|
51
|
-
*
|
|
52
|
-
* @throws {ShoushaiError} 枚数が不足している場合 (< 13)
|
|
53
|
-
* @throws {TahaiError} 枚数が超過している場合 (> 14)
|
|
54
|
-
*/
|
|
55
|
-
export function validateTehai(tehai) {
|
|
56
|
-
const count = calculateTehaiCount(tehai);
|
|
57
|
-
if (count < 13) {
|
|
58
|
-
throw new ShoushaiError();
|
|
59
|
-
}
|
|
60
|
-
if (count > 14) {
|
|
61
|
-
throw new TahaiError();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Type Guard for Tehai13
|
|
66
|
-
*/
|
|
67
|
-
export function isTehai13(tehai) {
|
|
68
|
-
try {
|
|
69
|
-
validateTehai13(tehai);
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Type Guard for Tehai14
|
|
78
|
-
*/
|
|
79
|
-
export function isTehai14(tehai) {
|
|
80
|
-
try {
|
|
81
|
-
validateTehai14(tehai);
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
package/dist/errors.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* riichi-mahjong ライブラリの基本エラークラス
|
|
3
|
-
* 全てのカスタムエラーはこのクラスを継承します。
|
|
4
|
-
*/
|
|
5
|
-
export declare class MahjongError extends Error {
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
constructor(message: string);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* ツモれなかった場合のエラー (少牌)
|
|
13
|
-
* 手牌が規定枚数(13枚)より少ない場合にスローされます。
|
|
14
|
-
*/
|
|
15
|
-
export declare class ShoushaiError extends MahjongError {
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
*/
|
|
19
|
-
constructor(message?: string);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* 切り忘れの場合のエラー (多牌)
|
|
23
|
-
* 手牌が規定枚数(13枚)より多い場合にスローされます。
|
|
24
|
-
*/
|
|
25
|
-
export declare class TahaiError extends MahjongError {
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
*/
|
|
29
|
-
constructor(message?: string);
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 引数が不正な場合のエラー
|
|
33
|
-
* 必要なパラメータが不足している、または不正な値の場合にスローされます。
|
|
34
|
-
*/
|
|
35
|
-
export declare class MahjongArgumentError extends MahjongError {
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
39
|
-
constructor(message: string);
|
|
40
|
-
}
|
package/dist/errors.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* riichi-mahjong ライブラリの基本エラークラス
|
|
3
|
-
* 全てのカスタムエラーはこのクラスを継承します。
|
|
4
|
-
*/
|
|
5
|
-
export class MahjongError extends Error {
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
constructor(message) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.name = "MahjongError";
|
|
12
|
-
// TypeScriptでカスタムエラーを正しく動作させるためのハック
|
|
13
|
-
// TypeScriptでカスタムエラーを正しく動作させるためのハック
|
|
14
|
-
Object.setPrototypeOf(this, MahjongError.prototype);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* ツモれなかった場合のエラー (少牌)
|
|
19
|
-
* 手牌が規定枚数(13枚)より少ない場合にスローされます。
|
|
20
|
-
*/
|
|
21
|
-
export class ShoushaiError extends MahjongError {
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
*/
|
|
25
|
-
constructor(message = "手牌が規定枚数(13枚)より少ないです。") {
|
|
26
|
-
super(message);
|
|
27
|
-
this.name = "ShoushaiError";
|
|
28
|
-
Object.setPrototypeOf(this, ShoushaiError.prototype);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 切り忘れの場合のエラー (多牌)
|
|
33
|
-
* 手牌が規定枚数(13枚)より多い場合にスローされます。
|
|
34
|
-
*/
|
|
35
|
-
export class TahaiError extends MahjongError {
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
39
|
-
constructor(message = "手牌が規定枚数(13枚)より多いです。") {
|
|
40
|
-
super(message);
|
|
41
|
-
this.name = "TahaiError";
|
|
42
|
-
Object.setPrototypeOf(this, TahaiError.prototype);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* 引数が不正な場合のエラー
|
|
47
|
-
* 必要なパラメータが不足している、または不正な値の場合にスローされます。
|
|
48
|
-
*/
|
|
49
|
-
export class MahjongArgumentError extends MahjongError {
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
*/
|
|
53
|
-
constructor(message) {
|
|
54
|
-
super(message);
|
|
55
|
-
this.name = "MahjongArgumentError";
|
|
56
|
-
Object.setPrototypeOf(this, MahjongArgumentError.prototype);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { calculateMentsuTeShanten } from "../shanten";
|
|
2
|
-
/**
|
|
3
|
-
* 手牌の受け入れ(有効牌)を計算する。
|
|
4
|
-
* 今回は面子手のみを対象とし、七対子や国士無双は考慮しない。
|
|
5
|
-
*
|
|
6
|
-
* @param tehai 手牌 (13枚)
|
|
7
|
-
* @returns シャンテン数を進める牌のリスト
|
|
8
|
-
*/
|
|
9
|
-
export function getUkeire(tehai) {
|
|
10
|
-
const currentShanten = calculateMentsuTeShanten(tehai);
|
|
11
|
-
const ukeireList = [];
|
|
12
|
-
// 全34種の牌について、1枚加えてシャンテン数が下がるか試す
|
|
13
|
-
for (let i = 0; i < 34; i++) {
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
15
|
-
const tile = i;
|
|
16
|
-
// 手牌のコピーを作成(副作用を防ぐため、常に新しいオブジェクトで試行)
|
|
17
|
-
// Tehai13に1枚足すので、厳密にはTehai14として扱う必要があるが、
|
|
18
|
-
// calculateMentsuTeShanten は Tehai<HaiKindId> を受け付けるので、
|
|
19
|
-
// 構造的に { closed, exposed } が適合していればOK。
|
|
20
|
-
// ただし、Tehai13型に準拠したオブジェクトに1枚足すと枚数オーバーになるため、
|
|
21
|
-
// バリデーションを通過させるために Tehai14 として構築するか、
|
|
22
|
-
// calculateMentsuTeShanten 側が Generics で受け入れる点を利用する。
|
|
23
|
-
// 配列のコピーを作成
|
|
24
|
-
const newClosed = [...tehai.closed, tile];
|
|
25
|
-
const newTehai = {
|
|
26
|
-
closed: newClosed,
|
|
27
|
-
exposed: tehai.exposed,
|
|
28
|
-
};
|
|
29
|
-
// シャンテン数を計算
|
|
30
|
-
// ここでバリデーションエラーが出ないように、calculateMentsuTeShanten 側は validateTehai を使用している。
|
|
31
|
-
const newShanten = calculateMentsuTeShanten(newTehai);
|
|
32
|
-
if (newShanten < currentShanten) {
|
|
33
|
-
ukeireList.push(tile);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return ukeireList;
|
|
37
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { MachiType } from "../../core/machi";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|