mj-simulator 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.
Files changed (85) hide show
  1. package/data/honor-table.bin +0 -0
  2. package/data/suit-table.bin +0 -0
  3. package/dist/cli.d.ts +1 -0
  4. package/dist/cli.js +278 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/core/constants.d.ts +13 -0
  7. package/dist/core/constants.js +19 -0
  8. package/dist/core/constants.js.map +1 -0
  9. package/dist/core/hand.d.ts +37 -0
  10. package/dist/core/hand.js +105 -0
  11. package/dist/core/hand.js.map +1 -0
  12. package/dist/core/remaining.d.ts +12 -0
  13. package/dist/core/remaining.js +26 -0
  14. package/dist/core/remaining.js.map +1 -0
  15. package/dist/core/tile.d.ts +45 -0
  16. package/dist/core/tile.js +140 -0
  17. package/dist/core/tile.js.map +1 -0
  18. package/dist/ev/ev-calculator.d.ts +10 -0
  19. package/dist/ev/ev-calculator.js +257 -0
  20. package/dist/ev/ev-calculator.js.map +1 -0
  21. package/dist/ev/types.d.ts +16 -0
  22. package/dist/ev/types.js +2 -0
  23. package/dist/ev/types.js.map +1 -0
  24. package/dist/index.d.ts +27 -0
  25. package/dist/index.js +27 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/init.d.ts +11 -0
  28. package/dist/init.js +24 -0
  29. package/dist/init.js.map +1 -0
  30. package/dist/mc/simulator.d.ts +18 -0
  31. package/dist/mc/simulator.js +11 -0
  32. package/dist/mc/simulator.js.map +1 -0
  33. package/dist/mc/wasm-bridge.d.ts +30 -0
  34. package/dist/mc/wasm-bridge.js +56 -0
  35. package/dist/mc/wasm-bridge.js.map +1 -0
  36. package/dist/models/danger.d.ts +34 -0
  37. package/dist/models/danger.js +147 -0
  38. package/dist/models/danger.js.map +1 -0
  39. package/dist/models/evaluation.d.ts +31 -0
  40. package/dist/models/evaluation.js +46 -0
  41. package/dist/models/evaluation.js.map +1 -0
  42. package/dist/scoring/decomposer.d.ts +7 -0
  43. package/dist/scoring/decomposer.js +106 -0
  44. package/dist/scoring/decomposer.js.map +1 -0
  45. package/dist/scoring/fu.d.ts +5 -0
  46. package/dist/scoring/fu.js +47 -0
  47. package/dist/scoring/fu.js.map +1 -0
  48. package/dist/scoring/score-calculator.d.ts +11 -0
  49. package/dist/scoring/score-calculator.js +164 -0
  50. package/dist/scoring/score-calculator.js.map +1 -0
  51. package/dist/scoring/types.d.ts +38 -0
  52. package/dist/scoring/types.js +2 -0
  53. package/dist/scoring/types.js.map +1 -0
  54. package/dist/scoring/wait-type.d.ts +11 -0
  55. package/dist/scoring/wait-type.js +65 -0
  56. package/dist/scoring/wait-type.js.map +1 -0
  57. package/dist/scoring/yaku.d.ts +7 -0
  58. package/dist/scoring/yaku.js +490 -0
  59. package/dist/scoring/yaku.js.map +1 -0
  60. package/dist/shanten/init.d.ts +9 -0
  61. package/dist/shanten/init.js +26 -0
  62. package/dist/shanten/init.js.map +1 -0
  63. package/dist/shanten/lookup-table.d.ts +37 -0
  64. package/dist/shanten/lookup-table.js +228 -0
  65. package/dist/shanten/lookup-table.js.map +1 -0
  66. package/dist/shanten/shanten-calculator.d.ts +18 -0
  67. package/dist/shanten/shanten-calculator.js +101 -0
  68. package/dist/shanten/shanten-calculator.js.map +1 -0
  69. package/dist/shanten/ukeire.d.ts +35 -0
  70. package/dist/shanten/ukeire.js +103 -0
  71. package/dist/shanten/ukeire.js.map +1 -0
  72. package/dist/types.d.ts +17 -0
  73. package/dist/types.js +2 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/worker-client.d.ts +42 -0
  76. package/dist/worker-client.js +83 -0
  77. package/dist/worker-client.js.map +1 -0
  78. package/dist/worker.d.ts +1 -0
  79. package/dist/worker.js +67 -0
  80. package/dist/worker.js.map +1 -0
  81. package/node_modules/mj-mc-wasm/mj_mc_wasm.d.ts +57 -0
  82. package/node_modules/mj-mc-wasm/mj_mc_wasm.js +235 -0
  83. package/node_modules/mj-mc-wasm/mj_mc_wasm_bg.wasm +0 -0
  84. package/node_modules/mj-mc-wasm/package.json +15 -0
  85. package/package.json +44 -0
Binary file
Binary file
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,278 @@
1
+ import { NUM_TILE_TYPES_WITH_RED } from "./core/constants.js";
2
+ import { handFromNotation, handToString, countTiles } from "./core/hand.js";
3
+ import { maxTilesForId, buildDefaultRemaining } from "./core/remaining.js";
4
+ import { tileToString, parseTiles, nextTile } from "./core/tile.js";
5
+ import { calculateShanten } from "./shanten/shanten-calculator.js";
6
+ import { calculateUkeire13, calculateUkeire14, mergeRedAcceptTiles } from "./shanten/ukeire.js";
7
+ import { calculateEV13, calculateEV14 } from "./ev/ev-calculator.js";
8
+ import { simulateDiscards } from "./mc/simulator.js";
9
+ import { evaluateDiscards } from "./models/evaluation.js";
10
+ import { getSuitTable, getHonorTable, isInitialized, setSuitTable, setHonorTable } from "./shanten/lookup-table.js";
11
+ import { initMCWasm, isWasmMCAvailable } from "./mc/wasm-bridge.js";
12
+ /** Node.js環境でテーブルをファイルから読み込む(生成の25秒を回避) */
13
+ async function loadTablesFromFile() {
14
+ try {
15
+ const { readFile } = await import("node:fs/promises");
16
+ const { fileURLToPath } = await import("node:url");
17
+ const { dirname, join } = await import("node:path");
18
+ const dir = dirname(fileURLToPath(import.meta.url));
19
+ const dataDir = join(dir, "..", "data");
20
+ const [suitBuf, honorBuf] = await Promise.all([
21
+ readFile(join(dataDir, "suit-table.bin")),
22
+ readFile(join(dataDir, "honor-table.bin")),
23
+ ]);
24
+ setSuitTable(new Int8Array(suitBuf.buffer, suitBuf.byteOffset, suitBuf.byteLength));
25
+ setHonorTable(new Int8Array(honorBuf.buffer, honorBuf.byteOffset, honorBuf.byteLength));
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ function shantenLabel(shanten) {
33
+ if (shanten === -1)
34
+ return "和了";
35
+ if (shanten === 0)
36
+ return "聴牌";
37
+ return `${shanten}向聴`;
38
+ }
39
+ function parseFlag(args, prefix) {
40
+ for (const a of args) {
41
+ if (a.startsWith(prefix)) {
42
+ return a.slice(prefix.length);
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ async function main() {
48
+ // テーブルをファイルから読み込み(毎回25秒の生成を回避)
49
+ if (!isInitialized()) {
50
+ await loadTablesFromFile();
51
+ }
52
+ const args = process.argv.slice(2);
53
+ // フラグ解析
54
+ const hasNoRed = args.includes("--no-red");
55
+ const hasEV = args.includes("--ev");
56
+ const hasMC = args.includes("--mc");
57
+ const hasRiichi = args.includes("--riichi");
58
+ const turnStr = parseFlag(args, "--turn=");
59
+ const doraStr = parseFlag(args, "--dora=");
60
+ const uraStr = parseFlag(args, "--ura=");
61
+ const simsStr = parseFlag(args, "--sims=");
62
+ const riichiTurnStr = parseFlag(args, "--riichi-turn=");
63
+ const positionalArgs = args.filter((a) => !a.startsWith("--"));
64
+ if (positionalArgs.length === 0) {
65
+ console.log("使い方: tsx src/cli.ts <手牌> [見えている牌] [--no-red] [--ev] [--mc] [--turn=N] [--dora=牌] [--ura=N] [--sims=N] [--riichi] [--riichi-turn=N]");
66
+ console.log("例: tsx src/cli.ts 123m456p789s1122z");
67
+ console.log(" tsx src/cli.ts 123m456p789s1122z --ev --dora=1z");
68
+ console.log(" tsx src/cli.ts 123m456p789s1122z --ev --ura=0 (裏ドラなし)");
69
+ console.log(" tsx src/cli.ts 566789m0p128899p4s --mc --dora=6p --turn=3");
70
+ console.log(" tsx src/cli.ts 566789m0p128899p4s --mc --dora=6p --turn=3 --riichi --riichi-turn=5");
71
+ process.exit(1);
72
+ }
73
+ const useRedDora = !hasNoRed;
74
+ // --ura=N: 裏ドラ枚数 (--ev時デフォルト1、それ以外0)
75
+ const uraDoraCount = uraStr !== undefined ? parseInt(uraStr) : (hasEV ? 1 : 0);
76
+ const handNotation = positionalArgs[0];
77
+ const hand = handFromNotation(handNotation);
78
+ const tileCount = countTiles(hand);
79
+ if (tileCount < 1 || tileCount > 14) {
80
+ console.error(`エラー: 手牌の枚数が不正です (${tileCount}枚)`);
81
+ process.exit(1);
82
+ }
83
+ // 見えている牌(ドラ表示牌・捨て牌など)
84
+ let visibleHand;
85
+ if (positionalArgs[1]) {
86
+ visibleHand = handFromNotation(positionalArgs[1]);
87
+ }
88
+ // 残り牌の計算
89
+ let remaining;
90
+ if (visibleHand) {
91
+ remaining = new Array(NUM_TILE_TYPES_WITH_RED);
92
+ for (let i = 0; i < NUM_TILE_TYPES_WITH_RED; i++) {
93
+ remaining[i] = maxTilesForId(i, useRedDora) - hand[i] - (visibleHand[i] ?? 0);
94
+ if (remaining[i] < 0)
95
+ remaining[i] = 0;
96
+ }
97
+ }
98
+ // ドラ表示牌
99
+ const doraIndicators = doraStr ? parseTiles(doraStr) : [];
100
+ // ドラ表示牌は見えている牌なので残り山から引く
101
+ if (doraIndicators.length > 0) {
102
+ if (!remaining) {
103
+ remaining = buildDefaultRemaining(hand, useRedDora);
104
+ }
105
+ for (const d of doraIndicators) {
106
+ if (remaining[d] > 0)
107
+ remaining[d]--;
108
+ }
109
+ }
110
+ console.log(`手牌: ${handToString(hand)} (${tileCount}枚)`);
111
+ const shanten = calculateShanten(hand);
112
+ console.log(`シャンテン数: ${shanten} (${shantenLabel(shanten)})`);
113
+ if (shanten === -1) {
114
+ console.log("和了形です!");
115
+ return;
116
+ }
117
+ console.log("");
118
+ const t0 = Date.now();
119
+ if (tileCount === 13) {
120
+ // 13枚: 受入牌を表示
121
+ const options = { useRedDora };
122
+ const { acceptTiles } = calculateUkeire13(hand, remaining, options);
123
+ const effectiveRemaining = remaining ?? buildDefaultRemaining(hand, useRedDora);
124
+ const merged = mergeRedAcceptTiles(acceptTiles, effectiveRemaining);
125
+ const mergedCount = merged.reduce((s, e) => s + e.count, 0);
126
+ console.log(`受入: ${merged.length}種 ${mergedCount}枚`);
127
+ if (merged.length > 0) {
128
+ const tileStrs = merged.map((e) => `${tileToString(e.tile)}(${e.count})`);
129
+ console.log(` [${tileStrs.join(", ")}]`);
130
+ }
131
+ if (hasEV) {
132
+ const currentTurn = turnStr ? parseInt(turnStr) : 1;
133
+ const context = {
134
+ seatWind: 28,
135
+ roundWind: 27,
136
+ doraIndicators,
137
+ useRedDora,
138
+ riichi: true,
139
+ uraDoraCount,
140
+ };
141
+ const ev = calculateEV13(hand, {
142
+ context,
143
+ remaining: effectiveRemaining,
144
+ currentTurn,
145
+ });
146
+ console.log(`\n期待値: ${Math.round(ev)}点`);
147
+ }
148
+ }
149
+ else if (tileCount === 14) {
150
+ if (hasMC) {
151
+ // WASM MC初期化(Rust内でスコア計算も完結)
152
+ if (isInitialized()) {
153
+ await initMCWasm(getSuitTable(), getHonorTable());
154
+ }
155
+ // 14枚 + --mc: MCシミュレーション
156
+ const currentTurn = turnStr ? parseInt(turnStr) : 1;
157
+ const maxTurns = 18;
158
+ const turnsLeft = Math.max(1, maxTurns - currentTurn + 1);
159
+ const numSims = simsStr ? parseInt(simsStr) : 3000;
160
+ const effectiveRemaining = remaining ?? buildDefaultRemaining(hand, useRedDora);
161
+ const context = {
162
+ seatWind: 28,
163
+ roundWind: 27,
164
+ doraIndicators,
165
+ useRedDora,
166
+ riichi: true,
167
+ uraDoraCount: uraStr !== undefined ? parseInt(uraStr) : 1,
168
+ };
169
+ // ドラ表示
170
+ if (doraIndicators.length > 0) {
171
+ const doraDisp = doraIndicators.map(d => tileToString(d)).join(", ");
172
+ const doraTiles = doraIndicators.map(d => tileToString(nextTile(d))).join(", ");
173
+ console.log(`ドラ表示: ${doraDisp} (ドラ: ${doraTiles})`);
174
+ }
175
+ console.log(`巡目: ${currentTurn} (残り${turnsLeft}巡)`);
176
+ console.log(`シミュレーション回数: ${numSims}回/候補`);
177
+ console.log(`エンジン: ${isWasmMCAvailable() ? 'WASM (Rust)' : 'TypeScript'}\n`);
178
+ const mcResults = simulateDiscards(hand, {
179
+ context,
180
+ remaining: effectiveRemaining,
181
+ turnsLeft,
182
+ numSims,
183
+ });
184
+ if (hasRiichi) {
185
+ // リーチ者ありの場合、防御EVも計算
186
+ const riichiTurn = riichiTurnStr ? parseInt(riichiTurnStr) : currentTurn;
187
+ const evalResults = evaluateDiscards(hand, mcResults, {
188
+ turn: currentTurn,
189
+ hasRiichiPlayer: true,
190
+ riichiTurn,
191
+ visibleTiles: effectiveRemaining, // TODO: 場に見えている牌の正確な計算
192
+ });
193
+ console.log("打牌候補 (評価値順):");
194
+ for (const r of evalResults) {
195
+ const label = shantenLabel(r.shantenAfter);
196
+ console.log(` 打${tileToString(r.discard).padEnd(3)}: ${label.padEnd(4)} 受入${String(r.acceptCount).padStart(3)}枚 攻撃EV ${Math.round(r.attackEV).toString().padStart(6)}点 防御EV ${Math.round(r.defenseEV).toString().padStart(5)}点 総合EV ${Math.round(r.totalEV).toString().padStart(6)}点`);
197
+ }
198
+ }
199
+ else {
200
+ // リーチ者なし: MC結果をそのまま表示
201
+ console.log("打牌候補 (EV順):");
202
+ for (const r of mcResults) {
203
+ const label = shantenLabel(r.shantenAfter);
204
+ const winPct = (r.winRate * 100).toFixed(1);
205
+ console.log(` 打${tileToString(r.discard).padEnd(3)}: ${label.padEnd(4)} 受入${String(r.acceptCount).padStart(3)}枚 和了率${winPct.padStart(5)}% 平均打点${Math.round(r.avgPoints).toString().padStart(6)} EV ${Math.round(r.ev).toString().padStart(6)}点`);
206
+ }
207
+ }
208
+ }
209
+ else if (hasEV) {
210
+ // 14枚 + --ev: 期待値計算
211
+ const currentTurn = turnStr ? parseInt(turnStr) : 1;
212
+ const effectiveRemaining = remaining ?? buildDefaultRemaining(hand, useRedDora);
213
+ const context = {
214
+ seatWind: 28, // 南 (デフォルト)
215
+ roundWind: 27, // 東 (デフォルト)
216
+ doraIndicators,
217
+ useRedDora,
218
+ riichi: true, // 聴牌時リーチ
219
+ uraDoraCount,
220
+ };
221
+ const evResults = calculateEV14(hand, {
222
+ context,
223
+ remaining: effectiveRemaining,
224
+ currentTurn,
225
+ });
226
+ console.log("打牌候補 (期待値順):");
227
+ for (const r of evResults) {
228
+ hand[r.discard]--;
229
+ let rem;
230
+ if (remaining) {
231
+ rem = remaining;
232
+ }
233
+ else {
234
+ rem = buildDefaultRemaining(hand, useRedDora);
235
+ rem[r.discard]--;
236
+ }
237
+ const { acceptTiles } = calculateUkeire13(hand, rem, { useRedDora });
238
+ hand[r.discard]++;
239
+ const merged = mergeRedAcceptTiles(acceptTiles, rem);
240
+ const mergedCount = merged.reduce((s, e) => s + e.count, 0);
241
+ const tileStrs = merged.map((e) => `${tileToString(e.tile)}(${e.count})`);
242
+ const label = shantenLabel(r.shantenAfter);
243
+ const evStr = Math.round(r.ev).toString();
244
+ console.log(` 切り ${tileToString(r.discard).padEnd(3)}: ${label.padEnd(4)} 受入 ${String(merged.length).padStart(2)}種 ${String(mergedCount).padStart(3)}枚 EV ${evStr.padStart(6)}点 [${tileStrs.join(", ")}]`);
245
+ }
246
+ }
247
+ else {
248
+ // 14枚: 既存の打牌候補表示
249
+ console.log("打牌候補:");
250
+ const options = { useRedDora };
251
+ const results = calculateUkeire14(hand, remaining, options);
252
+ for (const r of results) {
253
+ hand[r.discard]--;
254
+ let effectiveRemaining;
255
+ if (remaining) {
256
+ effectiveRemaining = remaining;
257
+ }
258
+ else {
259
+ effectiveRemaining = buildDefaultRemaining(hand, useRedDora);
260
+ effectiveRemaining[r.discard]--;
261
+ }
262
+ hand[r.discard]++;
263
+ const merged = mergeRedAcceptTiles(r.acceptTiles, effectiveRemaining);
264
+ const mergedCount = merged.reduce((s, e) => s + e.count, 0);
265
+ const tileStrs = merged.map((e) => `${tileToString(e.tile)}(${e.count})`);
266
+ const label = shantenLabel(r.shantenAfter);
267
+ console.log(` 切り ${tileToString(r.discard).padEnd(3)}: ${label.padEnd(4)} 受入 ${String(merged.length).padStart(2)}種 ${String(mergedCount).padStart(3)}枚 [${tileStrs.join(", ")}]`);
268
+ }
269
+ }
270
+ }
271
+ else {
272
+ console.log("(13枚または14枚の手牌で受入解析を実行できます)");
273
+ }
274
+ const elapsed = Date.now() - t0;
275
+ console.log(`\n計算時間: ${(elapsed / 1000).toFixed(2)}s`);
276
+ }
277
+ main();
278
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const NUM_TILE_TYPES = 34;
2
+ export declare const SUIT_NUM = 9;
3
+ export declare const HONOR_NUM = 7;
4
+ export declare const NUM_SUITS = 4;
5
+ export declare const MANZU_OFFSET = 0;
6
+ export declare const PINZU_OFFSET = 9;
7
+ export declare const SOUZU_OFFSET = 18;
8
+ export declare const JIHAI_OFFSET = 27;
9
+ export declare const NUM_TILE_TYPES_WITH_RED = 37;
10
+ export declare const RED_MANZU_ID = 34;
11
+ export declare const RED_PINZU_ID = 35;
12
+ export declare const RED_SOUZU_ID = 36;
13
+ export declare const YAOCHU_IDS: readonly [0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33];
@@ -0,0 +1,19 @@
1
+ export const NUM_TILE_TYPES = 34;
2
+ export const SUIT_NUM = 9; // 数牌は9種
3
+ export const HONOR_NUM = 7; // 字牌は7種
4
+ export const NUM_SUITS = 4; // マンズ/ピンズ/ソーズ/字牌
5
+ // 牌ID範囲
6
+ export const MANZU_OFFSET = 0;
7
+ export const PINZU_OFFSET = 9;
8
+ export const SOUZU_OFFSET = 18;
9
+ export const JIHAI_OFFSET = 27;
10
+ // 赤ドラ
11
+ export const NUM_TILE_TYPES_WITH_RED = 37;
12
+ export const RED_MANZU_ID = 34; // 赤5m
13
+ export const RED_PINZU_ID = 35; // 赤5p
14
+ export const RED_SOUZU_ID = 36; // 赤5s
15
+ // 么九牌ID一覧(国士無双用)
16
+ export const YAOCHU_IDS = [
17
+ 0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33,
18
+ ]; // 1m,9m,1p,9p,1s,9s,東南西北白發中
19
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ;AACnC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,QAAQ;AACpC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,iBAAiB;AAE7C,QAAQ;AACR,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAC9B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAC9B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAE/B,MAAM;AACN,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,MAAM;AACtC,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,MAAM;AACtC,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,MAAM;AAEtC,iBAAiB;AACjB,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;CACvC,CAAC,CAAC,4BAA4B"}
@@ -0,0 +1,37 @@
1
+ import { TileId } from "./tile.js";
2
+ /** 手牌配列 (長さ37, 各要素は0-4, 34-36は赤ドラ) */
3
+ export type HandArray = number[];
4
+ /**
5
+ * 空の手牌を作成する
6
+ */
7
+ export declare function createHand(): HandArray;
8
+ /**
9
+ * 牌ID配列から手牌を作成する
10
+ */
11
+ export declare function handFromTiles(tiles: TileId[]): HandArray;
12
+ /**
13
+ * 文字列表記から手牌を作成する
14
+ * 例: "123m456p789s11z" → HandArray
15
+ */
16
+ export declare function handFromNotation(notation: string): HandArray;
17
+ /**
18
+ * 手牌を表示用文字列に変換する
19
+ * 例: "1m 2m 3m 4p 5p 6p 7s 8s 9s 東 東"
20
+ * 赤ドラは各色の5の前に出力される (例: "0m 5m")
21
+ */
22
+ export declare function handToString(hand: HandArray): string;
23
+ /**
24
+ * 手牌を短縮表記文字列に変換する
25
+ * 例: "123m456p789s11z"
26
+ * 赤ドラは "0" として各色の5の前に出力される
27
+ */
28
+ export declare function handToNotation(hand: HandArray): string;
29
+ /**
30
+ * 手牌の総枚数を返す
31
+ */
32
+ export declare function countTiles(hand: HandArray): number;
33
+ /**
34
+ * 手牌を色ごとに分割する(赤ドラは通常の5にマージ)
35
+ * @returns [萬子(9), 筒子(9), 索子(9), 字牌(7)]
36
+ */
37
+ export declare function splitToSuits(hand: HandArray): [number[], number[], number[], number[]];
@@ -0,0 +1,105 @@
1
+ import { NUM_TILE_TYPES, NUM_TILE_TYPES_WITH_RED, SUIT_NUM, HONOR_NUM, JIHAI_OFFSET, RED_MANZU_ID, RED_PINZU_ID, RED_SOUZU_ID } from "./constants.js";
2
+ import { parseTiles, tileToString } from "./tile.js";
3
+ /**
4
+ * 空の手牌を作成する
5
+ */
6
+ export function createHand() {
7
+ return new Array(NUM_TILE_TYPES_WITH_RED).fill(0);
8
+ }
9
+ /**
10
+ * 牌ID配列から手牌を作成する
11
+ */
12
+ export function handFromTiles(tiles) {
13
+ const hand = createHand();
14
+ for (const id of tiles) {
15
+ hand[id]++;
16
+ }
17
+ return hand;
18
+ }
19
+ /**
20
+ * 文字列表記から手牌を作成する
21
+ * 例: "123m456p789s11z" → HandArray
22
+ */
23
+ export function handFromNotation(notation) {
24
+ return handFromTiles(parseTiles(notation));
25
+ }
26
+ /**
27
+ * 手牌を表示用文字列に変換する
28
+ * 例: "1m 2m 3m 4p 5p 6p 7s 8s 9s 東 東"
29
+ * 赤ドラは各色の5の前に出力される (例: "0m 5m")
30
+ */
31
+ export function handToString(hand) {
32
+ const parts = [];
33
+ const redIds = [RED_MANZU_ID, RED_PINZU_ID, RED_SOUZU_ID];
34
+ const normalFiveIds = [4, 13, 22]; // 通常5m, 5p, 5s
35
+ for (let i = 0; i < NUM_TILE_TYPES; i++) {
36
+ // 通常の5の位置で赤ドラを先に出力
37
+ const redIdx = normalFiveIds.indexOf(i);
38
+ if (redIdx >= 0) {
39
+ for (let j = 0; j < (hand[redIds[redIdx]] ?? 0); j++) {
40
+ parts.push(tileToString(redIds[redIdx]));
41
+ }
42
+ }
43
+ for (let j = 0; j < hand[i]; j++) {
44
+ parts.push(tileToString(i));
45
+ }
46
+ }
47
+ return parts.join(" ");
48
+ }
49
+ /**
50
+ * 手牌を短縮表記文字列に変換する
51
+ * 例: "123m456p789s11z"
52
+ * 赤ドラは "0" として各色の5の前に出力される
53
+ */
54
+ export function handToNotation(hand) {
55
+ let result = "";
56
+ const suitChars = ["m", "p", "s", "z"];
57
+ const suitSizes = [SUIT_NUM, SUIT_NUM, SUIT_NUM, HONOR_NUM];
58
+ const redIds = [RED_MANZU_ID, RED_PINZU_ID, RED_SOUZU_ID];
59
+ let offset = 0;
60
+ for (let s = 0; s < 4; s++) {
61
+ let suitStr = "";
62
+ for (let i = 0; i < suitSizes[s]; i++) {
63
+ // 5の位置 (i===4) で赤ドラを先に出力(数牌のみ)
64
+ if (i === 4 && s < 3) {
65
+ for (let j = 0; j < (hand[redIds[s]] ?? 0); j++) {
66
+ suitStr += "0";
67
+ }
68
+ }
69
+ for (let j = 0; j < hand[offset + i]; j++) {
70
+ suitStr += String(i + 1);
71
+ }
72
+ }
73
+ if (suitStr.length > 0) {
74
+ result += suitStr + suitChars[s];
75
+ }
76
+ offset += suitSizes[s];
77
+ }
78
+ return result;
79
+ }
80
+ /**
81
+ * 手牌の総枚数を返す
82
+ */
83
+ export function countTiles(hand) {
84
+ let count = 0;
85
+ for (let i = 0; i < hand.length; i++) {
86
+ count += hand[i];
87
+ }
88
+ return count;
89
+ }
90
+ /**
91
+ * 手牌を色ごとに分割する(赤ドラは通常の5にマージ)
92
+ * @returns [萬子(9), 筒子(9), 索子(9), 字牌(7)]
93
+ */
94
+ export function splitToSuits(hand) {
95
+ const manzu = hand.slice(0, SUIT_NUM);
96
+ const pinzu = hand.slice(SUIT_NUM, SUIT_NUM * 2);
97
+ const souzu = hand.slice(SUIT_NUM * 2, SUIT_NUM * 3);
98
+ const jihai = hand.slice(JIHAI_OFFSET, JIHAI_OFFSET + HONOR_NUM);
99
+ // 赤ドラを通常の5にマージ
100
+ manzu[4] += hand[RED_MANZU_ID] ?? 0;
101
+ pinzu[4] += hand[RED_PINZU_ID] ?? 0;
102
+ souzu[4] += hand[RED_SOUZU_ID] ?? 0;
103
+ return [manzu, pinzu, souzu, jihai];
104
+ }
105
+ //# sourceMappingURL=hand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hand.js","sourceRoot":"","sources":["../../src/core/hand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /** 通常の5のID一覧 (5m=4, 5p=13, 5s=22) */
2
+ export declare const NORMAL_FIVE_IDS: Set<number>;
3
+ /** 赤ドラのID一覧 */
4
+ export declare const RED_IDS: Set<number>;
5
+ /** 牌IDごとの最大枚数を返す */
6
+ export declare function maxTilesForId(id: number, useRedDora: boolean): number;
7
+ /**
8
+ * 残り牌のデフォルト計算
9
+ * 赤あり: 通常5=3枚, 赤5=1枚
10
+ * 赤なし: 通常5=4枚, 赤5=0枚
11
+ */
12
+ export declare function buildDefaultRemaining(hand: number[], useRedDora: boolean): number[];
@@ -0,0 +1,26 @@
1
+ import { NUM_TILE_TYPES_WITH_RED, RED_MANZU_ID, RED_PINZU_ID, RED_SOUZU_ID } from "./constants.js";
2
+ /** 通常の5のID一覧 (5m=4, 5p=13, 5s=22) */
3
+ export const NORMAL_FIVE_IDS = new Set([4, 13, 22]);
4
+ /** 赤ドラのID一覧 */
5
+ export const RED_IDS = new Set([RED_MANZU_ID, RED_PINZU_ID, RED_SOUZU_ID]);
6
+ /** 牌IDごとの最大枚数を返す */
7
+ export function maxTilesForId(id, useRedDora) {
8
+ if (RED_IDS.has(id))
9
+ return useRedDora ? 1 : 0;
10
+ if (NORMAL_FIVE_IDS.has(id))
11
+ return useRedDora ? 3 : 4;
12
+ return 4;
13
+ }
14
+ /**
15
+ * 残り牌のデフォルト計算
16
+ * 赤あり: 通常5=3枚, 赤5=1枚
17
+ * 赤なし: 通常5=4枚, 赤5=0枚
18
+ */
19
+ export function buildDefaultRemaining(hand, useRedDora) {
20
+ const rem = new Array(NUM_TILE_TYPES_WITH_RED);
21
+ for (let i = 0; i < NUM_TILE_TYPES_WITH_RED; i++) {
22
+ rem[i] = Math.max(0, maxTilesForId(i, useRedDora) - hand[i]);
23
+ }
24
+ return rem;
25
+ }
26
+ //# sourceMappingURL=remaining.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remaining.js","sourceRoot":"","sources":["../../src/core/remaining.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnG,qCAAqC;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD,eAAe;AACf,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAE3E,oBAAoB;AACpB,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,UAAmB;IAC3D,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAc,EAAE,UAAmB;IACvE,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,45 @@
1
+ /** 牌ID (0-33, 赤ドラ: 34-36) */
2
+ export type TileId = number;
3
+ /** 牌の色 */
4
+ export type TileSuit = "m" | "p" | "s" | "z";
5
+ /**
6
+ * 赤ドラかどうかを返す
7
+ */
8
+ export declare function isRedTile(id: TileId): boolean;
9
+ /**
10
+ * 赤ドラIDを対応する通常の5に変換する(通常牌はそのまま返す)
11
+ */
12
+ export declare function toNormalTile(id: TileId): TileId;
13
+ /**
14
+ * 牌IDの色インデックスを返す (0=萬子, 1=筒子, 2=索子, 3=字牌)
15
+ */
16
+ export declare function getSuitIndex(id: TileId): number;
17
+ /**
18
+ * 牌IDの色を返す
19
+ */
20
+ export declare function getSuit(id: TileId): TileSuit;
21
+ /**
22
+ * 牌IDの数字を返す (1-9, 字牌は1-7, 赤ドラは5)
23
+ */
24
+ export declare function getNum(id: TileId): number;
25
+ /**
26
+ * 牌IDが么九牌かどうかを返す
27
+ */
28
+ export declare function isYaochu(id: TileId): boolean;
29
+ /**
30
+ * 牌IDを文字列に変換する (例: 0 → "1m", 27 → "東", 34 → "0m")
31
+ */
32
+ export declare function tileToString(id: TileId): string;
33
+ /**
34
+ * ドラ表示牌から実際のドラ牌を返す
35
+ * 数牌: 1→2→...→9→1 (循環)
36
+ * 風牌: 東→南→西→北→東 (循環)
37
+ * 三元牌: 白→發→中→白 (循環)
38
+ */
39
+ export declare function nextTile(id: TileId): TileId;
40
+ /**
41
+ * 牌表記文字列をパースして牌ID配列を返す
42
+ * 例: "123m456p" → [0, 1, 2, 12, 13, 14]
43
+ * "東南白" → [27, 28, 32]
44
+ */
45
+ export declare function parseTiles(notation: string): TileId[];