labag 2.4.3 → 2.5.1

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/labag.d.ts CHANGED
@@ -20,7 +20,7 @@ export declare class LaBaG {
20
20
  /** 當前轉出的圖案組合 */
21
21
  patterns: [Pattern | null, Pattern | null, Pattern | null];
22
22
  /** 遊戲模式列表 */
23
- modes: Mode[];
23
+ modes: Mode<any>[];
24
24
  /** 事件監聽器列表 */
25
25
  eventListeners: Record<LaBaGEvent, ((game: LaBaG) => void)[]>;
26
26
  /**
@@ -49,7 +49,7 @@ export declare class LaBaG {
49
49
  * 新增遊戲模式。
50
50
  * @param mode - 要新增的模式。
51
51
  */
52
- addMode(mode: Mode): void;
52
+ addMode(mode: Mode<any>): void;
53
53
  /**
54
54
  * 檢查遊戲是否正在進行中(未達次數上限)。
55
55
  * @returns 如果遊戲仍在進行中則返回 true,否則返回 false。
@@ -59,7 +59,7 @@ export declare class LaBaG {
59
59
  * 取得目前遊戲的相關設定
60
60
  */
61
61
  getCurrentConfig(): {
62
- modes: Mode[];
62
+ modes: Mode<any>[];
63
63
  ranges: {
64
64
  threshold: number;
65
65
  pattern: Pattern;
package/dist/labag.js CHANGED
@@ -52,7 +52,10 @@ class LaBaG {
52
52
  * @param event - 要觸發的事件名稱。
53
53
  */
54
54
  emit(event) {
55
- [...this.eventListeners[event]].forEach((fn) => fn(this));
55
+ const listeners = this.eventListeners[event];
56
+ for (let i = 0; i < listeners.length; i++) {
57
+ listeners[i](this);
58
+ }
56
59
  }
57
60
  /**
58
61
  * 新增事件監聽器。
@@ -110,11 +113,12 @@ class LaBaG {
110
113
  kachu: 0,
111
114
  rrr: 0,
112
115
  };
113
- activeModes.forEach((mode) => {
114
- Object.entries(mode.rates).forEach(([patternName, rate]) => {
115
- combinedRates[patternName] += rate;
116
- });
117
- });
116
+ for (let i = 0; i < activeModes.length; i++) {
117
+ const mode = activeModes[i];
118
+ for (const patternName in mode.rates) {
119
+ combinedRates[patternName] += mode.rates[patternName];
120
+ }
121
+ }
118
122
  // 預先計算合併後的區間
119
123
  const ranges = [];
120
124
  let acc = 0;
@@ -154,22 +158,19 @@ class LaBaG {
154
158
  rollSlots() {
155
159
  const { ranges } = this.getCurrentConfig();
156
160
  const rangesAcc = ranges.length > 0 ? ranges[ranges.length - 1].threshold : 0;
157
- // 產生 3 個隨機數字
158
- this.randNums = [
159
- (0, randInt_1.randInt)(1, rangesAcc),
160
- (0, randInt_1.randInt)(1, rangesAcc),
161
- (0, randInt_1.randInt)(1, rangesAcc),
162
- ];
163
- this.randNums.forEach((num, index) => {
164
- // 根據預先計算的區間找到對應的圖案
165
- const match = ranges.find((r) => num <= r.threshold);
166
- if (match) {
167
- this.patterns[index] = match.pattern;
161
+ // 產生 3 個隨機數字並直接尋找對應圖案
162
+ for (let i = 0; i < 3; i++) {
163
+ const num = (0, randInt_1.randInt)(1, rangesAcc);
164
+ this.randNums[i] = num;
165
+ let matchedPattern = null;
166
+ for (let j = 0; j < ranges.length; j++) {
167
+ if (num <= ranges[j].threshold) {
168
+ matchedPattern = ranges[j].pattern;
169
+ break;
170
+ }
168
171
  }
169
- else {
170
- this.patterns[index] = null;
171
- }
172
- });
172
+ this.patterns[i] = matchedPattern;
173
+ }
173
174
  this.emit("rollSlots");
174
175
  }
175
176
  /**
package/dist/mode.d.ts CHANGED
@@ -1,9 +1,16 @@
1
1
  import { LaBaG } from "./labag";
2
2
  import { LaBaGEvent, Pattern, PatternName } from "./types";
3
+ interface ModeConfig<VariableType extends Record<string, any>> {
4
+ active: boolean;
5
+ name: string;
6
+ rates: Record<PatternName, number>;
7
+ eventListener?: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>>;
8
+ variable?: VariableType;
9
+ }
3
10
  /**
4
11
  * 代表遊戲的一種模式,包含機率設定和事件監聽器。
5
12
  */
6
- export declare class Mode {
13
+ export declare class Mode<VariableType extends Record<string, any> = Record<string, any>> implements ModeConfig<VariableType> {
7
14
  /** 模式是否啟用 */
8
15
  active: boolean;
9
16
  /** 模式名稱 */
@@ -15,9 +22,9 @@ export declare class Mode {
15
22
  pattern: Pattern;
16
23
  }[];
17
24
  /** 事件監聽器 */
18
- eventListener: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>>;
25
+ eventListener: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>>;
19
26
  /** 模式專屬的變數儲存空間 */
20
- variable: Record<string, any>;
27
+ variable: VariableType;
21
28
  /** 機率總和 */
22
29
  /**
23
30
  * 建立一個新的模式。
@@ -26,5 +33,6 @@ export declare class Mode {
26
33
  * @param rates - 各圖案的機率設定。
27
34
  * @param eventListener - 事件監聽器。
28
35
  */
29
- constructor(active: boolean, name: string, rates: Record<PatternName, number>, eventListener?: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>>, variable?: Record<string, any>);
36
+ constructor(active: boolean, name: string, rates: Record<PatternName, number>, eventListener?: Partial<Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>>, variable?: VariableType);
30
37
  }
38
+ export {};
@@ -1,3 +1,20 @@
1
1
  import { Mode } from "../mode";
2
- declare const _default: Mode;
2
+ declare const _default: Mode<{
3
+ times: number;
4
+ rate: number;
5
+ randNum: number;
6
+ count: number;
7
+ pattern: {
8
+ name: string;
9
+ scores: number[];
10
+ };
11
+ extendTimes: number;
12
+ bindPattern: {
13
+ readonly name: "gss";
14
+ readonly scores: [800, 400, 180];
15
+ };
16
+ bonusTimes: number;
17
+ requiredBindPatternCount: number;
18
+ mutiplier: number;
19
+ }>;
3
20
  export default _default;
@@ -1,8 +1,94 @@
1
1
  export declare const modes: {
2
- pikachu: import("..").Mode;
3
- superhhh: import("..").Mode;
4
- greenwei: import("..").Mode;
5
- normal: import("..").Mode;
2
+ pikachu: import("..").Mode<{
3
+ times: number;
4
+ pattern: {
5
+ name: string;
6
+ scores: number[];
7
+ };
8
+ bindPattern: {
9
+ readonly name: "kachu";
10
+ readonly scores: [12000, 8000, 1250];
11
+ };
12
+ bonusRounds: number;
13
+ }>;
14
+ superhhh: import("..").Mode<{
15
+ times: number;
16
+ rate: number;
17
+ score: number;
18
+ randNum: number;
19
+ bindPattern: {
20
+ readonly name: "hhh";
21
+ readonly scores: [1500, 800, 300];
22
+ };
23
+ bonusTimes: number;
24
+ pattern: {
25
+ name: string;
26
+ scores: number[];
27
+ };
28
+ extendTimes: number;
29
+ }>;
30
+ greenwei: import("..").Mode<{
31
+ times: number;
32
+ rate: number;
33
+ randNum: number;
34
+ count: number;
35
+ pattern: {
36
+ name: string;
37
+ scores: number[];
38
+ };
39
+ extendTimes: number;
40
+ bindPattern: {
41
+ readonly name: "gss";
42
+ readonly scores: [800, 400, 180];
43
+ };
44
+ bonusTimes: number;
45
+ requiredBindPatternCount: number;
46
+ mutiplier: number;
47
+ }>;
48
+ normal: import("..").Mode<Record<string, any>>;
6
49
  };
7
50
  export type ModeName = keyof typeof modes;
8
- export declare const modeList: import("..").Mode[];
51
+ export declare const modeList: (import("..").Mode<{
52
+ times: number;
53
+ rate: number;
54
+ randNum: number;
55
+ count: number;
56
+ pattern: {
57
+ name: string;
58
+ scores: number[];
59
+ };
60
+ extendTimes: number;
61
+ bindPattern: {
62
+ readonly name: "gss";
63
+ readonly scores: [800, 400, 180];
64
+ };
65
+ bonusTimes: number;
66
+ requiredBindPatternCount: number;
67
+ mutiplier: number;
68
+ }> | import("..").Mode<Record<string, any>> | import("..").Mode<{
69
+ times: number;
70
+ pattern: {
71
+ name: string;
72
+ scores: number[];
73
+ };
74
+ bindPattern: {
75
+ readonly name: "kachu";
76
+ readonly scores: [12000, 8000, 1250];
77
+ };
78
+ bonusRounds: number;
79
+ }> | import("..").Mode<{
80
+ times: number;
81
+ rate: number;
82
+ score: number;
83
+ randNum: number;
84
+ bindPattern: {
85
+ readonly name: "hhh";
86
+ readonly scores: [1500, 800, 300];
87
+ };
88
+ bonusTimes: number;
89
+ pattern: {
90
+ name: string;
91
+ scores: number[];
92
+ };
93
+ extendTimes: number;
94
+ }>)[];
@@ -1,3 +1,3 @@
1
1
  import { Mode } from "../mode";
2
- declare const _default: Mode;
2
+ declare const _default: Mode<Record<string, any>>;
3
3
  export default _default;
@@ -1,3 +1,14 @@
1
1
  import { Mode } from "../mode";
2
- declare const _default: Mode;
2
+ declare const _default: Mode<{
3
+ times: number;
4
+ pattern: {
5
+ name: string;
6
+ scores: number[];
7
+ };
8
+ bindPattern: {
9
+ readonly name: "kachu";
10
+ readonly scores: [12000, 8000, 1250];
11
+ };
12
+ bonusRounds: number;
13
+ }>;
3
14
  export default _default;
@@ -1,3 +1,18 @@
1
1
  import { Mode } from "../mode";
2
- declare const _default: Mode;
2
+ declare const _default: Mode<{
3
+ times: number;
4
+ rate: number;
5
+ score: number;
6
+ randNum: number;
7
+ bindPattern: {
8
+ readonly name: "hhh";
9
+ readonly scores: [1500, 800, 300];
10
+ };
11
+ bonusTimes: number;
12
+ pattern: {
13
+ name: string;
14
+ scores: number[];
15
+ };
16
+ extendTimes: number;
17
+ }>;
3
18
  export default _default;
@@ -21,48 +21,39 @@ class RecordChecker {
21
21
  * @returns 計算出的分數。
22
22
  */
23
23
  calculateScore(record) {
24
- // 重置遊戲狀態
24
+ // 警告:此操作會重置並覆蓋當前傳入的遊戲實例狀態
25
25
  this.game.init();
26
26
  this.game.times = record.times;
27
- // 使用 any 類型來存取私有方法
28
- const gameAny = this.game;
29
27
  for (const round of record.rounds) {
30
28
  if (!this.game.isRunning()) {
31
29
  throw new Error("遊戲次數已達上限,無法繼續遊玩。");
32
30
  }
33
31
  // 1. 回合開始
34
- gameAny.roundStart();
32
+ this.game["roundStart"]();
35
33
  // 2. 設定隨機數字與圖案 (模擬 rollSlots)
36
34
  const { ranges } = this.game.getCurrentConfig();
37
- this.game.randNums = [
38
- round.randNums["0"],
39
- round.randNums["1"],
40
- round.randNums["2"],
41
- ];
42
- this.game.randNums.forEach((num, index) => {
35
+ for (let i = 0; i < 3; i++) {
36
+ const num = round.randNums?.[i.toString()] ?? 0;
37
+ this.game.randNums[i] = num;
43
38
  const match = ranges.find((r) => num <= r.threshold);
44
- if (match) {
45
- this.game.patterns[index] = match.pattern;
46
- }
47
- else {
48
- this.game.patterns[index] = null;
49
- }
50
- });
39
+ this.game.patterns[i] = match ? match.pattern : null;
40
+ }
51
41
  // 觸發 rollSlots 事件,讓模式執行其邏輯 (例如 greenwei 產生隨機數)
52
- gameAny.emit("rollSlots");
42
+ this.game["emit"]("rollSlots");
53
43
  // 3. 覆蓋模式的隨機變數 (確保使用紀錄中的數值)
54
44
  this.game.modes.forEach((mode) => {
55
- if (round.randNums[mode.name] !== undefined) {
56
- mode.variable.randNum = round.randNums[mode.name];
45
+ const recordedNum = round.randNums?.[mode.name];
46
+ if (recordedNum !== undefined && mode.variable) {
47
+ mode.variable.randNum = recordedNum;
57
48
  }
58
49
  });
59
50
  // 4. 計算分數
60
- gameAny.calculateScore();
51
+ this.game["calculateScore"]();
61
52
  // 5. 回合結束
62
- gameAny.roundEnd();
53
+ this.game["roundEnd"]();
63
54
  }
64
55
  if (!this.game.isRunning()) {
65
- gameAny.gameOver();
56
+ this.game["gameOver"]();
66
57
  }
67
58
  return this.game.score;
68
59
  }
@@ -1,11 +1,11 @@
1
1
  import { LaBaG } from "./labag";
2
2
  export type RoundRecord = {
3
- randNums: Record<string, number>;
3
+ readonly randNums: Readonly<Record<string, number>>;
4
4
  };
5
5
  export type GameRecord = {
6
6
  times: number;
7
7
  score: number;
8
- rounds: RoundRecord[];
8
+ readonly rounds: ReadonlyArray<RoundRecord>;
9
9
  };
10
10
  export type RecorderOptions = {
11
11
  debug?: boolean;
@@ -14,13 +14,10 @@ export declare class Recorder {
14
14
  #private;
15
15
  private game;
16
16
  private score;
17
- private onRoundEndBound;
18
17
  private started;
19
18
  private debug;
20
19
  constructor(gameInstance: LaBaG, options?: RecorderOptions);
21
- get rounds(): {
22
- randNums: Record<string, number>;
23
- }[];
20
+ get rounds(): ReadonlyArray<RoundRecord>;
24
21
  private onRoundEnd;
25
22
  init(clearExisting?: boolean): void;
26
23
  dispose(): void;
package/dist/recorder.js CHANGED
@@ -5,28 +5,26 @@ class Recorder {
5
5
  game;
6
6
  #rounds = [];
7
7
  score = 0;
8
- onRoundEndBound;
9
8
  started = false;
10
9
  debug = false;
11
10
  constructor(gameInstance, options) {
12
11
  this.game = gameInstance;
13
- this.onRoundEndBound = this.onRoundEnd.bind(this);
14
- this.debug = !!options?.debug;
12
+ this.debug = options?.debug ?? false;
15
13
  }
16
14
  get rounds() {
17
- return this.#rounds.map((r) => ({ ...r }));
15
+ return this.#rounds;
18
16
  }
19
- onRoundEnd(g) {
17
+ onRoundEnd = (g) => {
20
18
  const randNums = {};
21
19
  g.randNums.forEach((value, key) => {
22
- if (!isNaN(value)) {
20
+ if (typeof value === "number" && !Number.isNaN(value)) {
23
21
  randNums[key] = value;
24
22
  }
25
23
  });
26
24
  // 收集各模式的 randNum(若為數值且有效)
27
25
  g.modes.forEach((mode) => {
28
26
  const rn = mode?.variable?.randNum;
29
- if (!isNaN(rn)) {
27
+ if (typeof rn === "number" && !Number.isNaN(rn)) {
30
28
  randNums[mode.name] = rn;
31
29
  }
32
30
  });
@@ -40,7 +38,7 @@ class Recorder {
40
38
  });
41
39
  this.#rounds.push(round);
42
40
  this.score = g.score;
43
- }
41
+ };
44
42
  init(clearExisting = true) {
45
43
  if (this.started)
46
44
  return;
@@ -48,14 +46,14 @@ class Recorder {
48
46
  this.clear();
49
47
  }
50
48
  if (typeof this.game.addEventListener === "function") {
51
- this.game.addEventListener("roundEnd", this.onRoundEndBound);
49
+ this.game.addEventListener("roundEnd", this.onRoundEnd);
52
50
  this.started = true;
53
51
  }
54
52
  }
55
53
  dispose() {
56
54
  if (!this.started)
57
55
  return;
58
- this.game.removeEventListener("roundEnd", this.onRoundEndBound);
56
+ this.game.removeEventListener("roundEnd", this.onRoundEnd);
59
57
  this.started = false;
60
58
  }
61
59
  clear() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "labag",
3
- "version": "2.4.3",
3
+ "version": "2.5.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/labag.ts CHANGED
@@ -23,7 +23,7 @@ export class LaBaG {
23
23
  /** 當前轉出的圖案組合 */
24
24
  patterns: [Pattern | null, Pattern | null, Pattern | null];
25
25
  /** 遊戲模式列表 */
26
- modes: Mode[];
26
+ modes: Mode<any>[];
27
27
  /** 事件監聽器列表 */
28
28
  eventListeners: Record<LaBaGEvent, ((game: LaBaG) => void)[]>;
29
29
 
@@ -55,7 +55,10 @@ export class LaBaG {
55
55
  * @param event - 要觸發的事件名稱。
56
56
  */
57
57
  private emit(event: LaBaGEvent) {
58
- [...this.eventListeners[event]].forEach((fn) => fn(this));
58
+ const listeners = this.eventListeners[event];
59
+ for (let i = 0; i < listeners.length; i++) {
60
+ listeners[i](this);
61
+ }
59
62
  }
60
63
 
61
64
  /**
@@ -83,7 +86,7 @@ export class LaBaG {
83
86
  * 新增遊戲模式。
84
87
  * @param mode - 要新增的模式。
85
88
  */
86
- addMode(mode: Mode) {
89
+ addMode(mode: Mode<any>) {
87
90
  this.modes.push(mode);
88
91
  // 註冊特定模式的監聽器
89
92
  Object.entries(mode.eventListener).forEach(([event, listener]) => {
@@ -120,11 +123,12 @@ export class LaBaG {
120
123
  kachu: 0,
121
124
  rrr: 0,
122
125
  };
123
- activeModes.forEach((mode) => {
124
- Object.entries(mode.rates).forEach(([patternName, rate]) => {
125
- combinedRates[patternName as PatternName] += rate;
126
- });
127
- });
126
+ for (let i = 0; i < activeModes.length; i++) {
127
+ const mode = activeModes[i];
128
+ for (const patternName in mode.rates) {
129
+ combinedRates[patternName as PatternName] += mode.rates[patternName as PatternName];
130
+ }
131
+ }
128
132
 
129
133
  // 預先計算合併後的區間
130
134
  const ranges: { threshold: number; pattern: Pattern }[] = [];
@@ -170,22 +174,21 @@ export class LaBaG {
170
174
  const { ranges } = this.getCurrentConfig();
171
175
  const rangesAcc =
172
176
  ranges.length > 0 ? ranges[ranges.length - 1].threshold : 0;
173
- // 產生 3 個隨機數字
174
- this.randNums = [
175
- randInt(1, rangesAcc),
176
- randInt(1, rangesAcc),
177
- randInt(1, rangesAcc),
178
- ];
179
-
180
- this.randNums.forEach((num, index) => {
181
- // 根據預先計算的區間找到對應的圖案
182
- const match = ranges.find((r) => num <= r.threshold);
183
- if (match) {
184
- this.patterns[index] = match.pattern;
185
- } else {
186
- this.patterns[index] = null;
177
+
178
+ // 產生 3 個隨機數字並直接尋找對應圖案
179
+ for (let i = 0; i < 3; i++) {
180
+ const num = randInt(1, rangesAcc);
181
+ this.randNums[i] = num;
182
+
183
+ let matchedPattern: Pattern | null = null;
184
+ for (let j = 0; j < ranges.length; j++) {
185
+ if (num <= ranges[j].threshold) {
186
+ matchedPattern = ranges[j].pattern;
187
+ break;
188
+ }
187
189
  }
188
- });
190
+ this.patterns[i] = matchedPattern;
191
+ }
189
192
 
190
193
  this.emit("rollSlots");
191
194
  }
package/src/mode.ts CHANGED
@@ -1,11 +1,22 @@
1
1
  import { LaBaG } from "./labag";
2
2
  import { patterns } from "./pattern";
3
3
  import { LaBaGEvent, Pattern, PatternName } from "./types";
4
+ interface ModeConfig<VariableType extends Record<string, any>> {
5
+ active: boolean;
6
+ name: string;
7
+ rates: Record<PatternName, number>;
8
+ eventListener?: Partial<
9
+ Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>
10
+ >;
11
+ variable?: VariableType;
12
+ }
4
13
 
5
14
  /**
6
15
  * 代表遊戲的一種模式,包含機率設定和事件監聽器。
7
16
  */
8
- export class Mode{
17
+ export class Mode<
18
+ VariableType extends Record<string, any> = Record<string, any>,
19
+ > implements ModeConfig<VariableType> {
9
20
  /** 模式是否啟用 */
10
21
  active: boolean;
11
22
  /** 模式名稱 */
@@ -16,11 +27,11 @@ export class Mode{
16
27
  ranges: { threshold: number; pattern: Pattern }[];
17
28
  /** 事件監聽器 */
18
29
  eventListener: Partial<
19
- Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>
30
+ Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>
20
31
  >;
21
32
 
22
33
  /** 模式專屬的變數儲存空間 */
23
- variable: Record<string, any>;
34
+ variable: VariableType;
24
35
  /** 機率總和 */
25
36
 
26
37
  /**
@@ -35,15 +46,15 @@ export class Mode{
35
46
  name: string,
36
47
  rates: Record<PatternName, number>,
37
48
  eventListener?: Partial<
38
- Record<LaBaGEvent, (game: LaBaG, mode: Mode) => void>
49
+ Record<LaBaGEvent, (game: LaBaG, mode: Mode<VariableType>) => void>
39
50
  >,
40
- variable?: Record<string, any>
51
+ variable?: VariableType,
41
52
  ) {
42
53
  this.active = active;
43
54
  this.name = name;
44
55
  this.rates = rates;
45
56
  this.eventListener = eventListener ?? {};
46
- this.variable = variable ?? {};
57
+ this.variable = variable ?? ({} as VariableType);
47
58
 
48
59
  // 預先計算機率區間
49
60
  this.ranges = [];
@@ -24,58 +24,49 @@ export class RecordChecker {
24
24
  * @returns 計算出的分數。
25
25
  */
26
26
  calculateScore(record: GameRecord): number {
27
- // 重置遊戲狀態
27
+ // 警告:此操作會重置並覆蓋當前傳入的遊戲實例狀態
28
28
  this.game.init();
29
29
  this.game.times = record.times;
30
30
 
31
- // 使用 any 類型來存取私有方法
32
- const gameAny = this.game as any;
33
-
34
31
  for (const round of record.rounds) {
35
32
  if (!this.game.isRunning()) {
36
33
  throw new Error("遊戲次數已達上限,無法繼續遊玩。");
37
34
  }
38
35
 
39
36
  // 1. 回合開始
40
- gameAny.roundStart();
37
+ this.game["roundStart"]();
41
38
 
42
39
  // 2. 設定隨機數字與圖案 (模擬 rollSlots)
43
40
  const { ranges } = this.game.getCurrentConfig();
44
-
45
- this.game.randNums = [
46
- round.randNums["0"],
47
- round.randNums["1"],
48
- round.randNums["2"],
49
- ];
50
-
51
- this.game.randNums.forEach((num, index) => {
41
+
42
+ for (let i = 0; i < 3; i++) {
43
+ const num = round.randNums?.[i.toString()] ?? 0;
44
+ this.game.randNums[i] = num;
45
+
52
46
  const match = ranges.find((r) => num <= r.threshold);
53
- if (match) {
54
- this.game.patterns[index] = match.pattern;
55
- } else {
56
- this.game.patterns[index] = null;
57
- }
58
- });
47
+ this.game.patterns[i] = match ? match.pattern : null;
48
+ }
59
49
 
60
50
  // 觸發 rollSlots 事件,讓模式執行其邏輯 (例如 greenwei 產生隨機數)
61
- gameAny.emit("rollSlots");
51
+ this.game["emit"]("rollSlots");
62
52
 
63
53
  // 3. 覆蓋模式的隨機變數 (確保使用紀錄中的數值)
64
54
  this.game.modes.forEach((mode) => {
65
- if (round.randNums[mode.name] !== undefined) {
66
- mode.variable.randNum = round.randNums[mode.name];
55
+ const recordedNum = round.randNums?.[mode.name];
56
+ if (recordedNum !== undefined && mode.variable) {
57
+ mode.variable.randNum = recordedNum;
67
58
  }
68
59
  });
69
60
 
70
61
  // 4. 計算分數
71
- gameAny.calculateScore();
62
+ this.game["calculateScore"]();
72
63
 
73
64
  // 5. 回合結束
74
- gameAny.roundEnd();
65
+ this.game["roundEnd"]();
75
66
  }
76
67
 
77
68
  if (!this.game.isRunning()) {
78
- gameAny.gameOver();
69
+ this.game["gameOver"]();
79
70
  }
80
71
 
81
72
  return this.game.score;
package/src/recorder.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { LaBaG } from "./labag";
2
2
 
3
3
  export type RoundRecord = {
4
- randNums: Record<string, number>;
4
+ readonly randNums: Readonly<Record<string, number>>;
5
5
  };
6
6
 
7
7
  export type GameRecord = {
8
8
  times: number;
9
9
  score: number;
10
- rounds: RoundRecord[];
10
+ readonly rounds: ReadonlyArray<RoundRecord>;
11
11
  };
12
12
 
13
13
  export type RecorderOptions = {
@@ -17,25 +17,23 @@ export class Recorder {
17
17
  private game: LaBaG;
18
18
  #rounds: RoundRecord[] = [];
19
19
  private score: number = 0;
20
- private onRoundEndBound: (e: LaBaG) => void;
21
20
  private started = false;
22
21
  private debug = false;
23
22
 
24
23
  constructor(gameInstance: LaBaG, options?: RecorderOptions) {
25
24
  this.game = gameInstance;
26
- this.onRoundEndBound = this.onRoundEnd.bind(this);
27
- this.debug = !!options?.debug;
25
+ this.debug = options?.debug ?? false;
28
26
  }
29
27
 
30
- get rounds() {
31
- return this.#rounds.map((r) => ({ ...r }));
28
+ get rounds(): ReadonlyArray<RoundRecord> {
29
+ return this.#rounds;
32
30
  }
33
31
 
34
- private onRoundEnd(g: LaBaG) {
32
+ private onRoundEnd = (g: LaBaG) => {
35
33
  const randNums: Record<string, number> = {};
36
34
 
37
35
  g.randNums.forEach((value, key) => {
38
- if (!isNaN(value)) {
36
+ if (typeof value === "number" && !Number.isNaN(value)) {
39
37
  randNums[key] = value;
40
38
  }
41
39
  });
@@ -43,7 +41,7 @@ export class Recorder {
43
41
  // 收集各模式的 randNum(若為數值且有效)
44
42
  g.modes.forEach((mode) => {
45
43
  const rn = mode?.variable?.randNum;
46
- if (!isNaN(rn)) {
44
+ if (typeof rn === "number" && !Number.isNaN(rn)) {
47
45
  randNums[mode.name] = rn;
48
46
  }
49
47
  });
@@ -60,7 +58,7 @@ export class Recorder {
60
58
 
61
59
  this.#rounds.push(round);
62
60
  this.score = g.score;
63
- }
61
+ };
64
62
 
65
63
  init(clearExisting = true) {
66
64
  if (this.started) return;
@@ -68,14 +66,14 @@ export class Recorder {
68
66
  this.clear();
69
67
  }
70
68
  if (typeof this.game.addEventListener === "function") {
71
- this.game.addEventListener("roundEnd", this.onRoundEndBound);
69
+ this.game.addEventListener("roundEnd", this.onRoundEnd);
72
70
  this.started = true;
73
71
  }
74
72
  }
75
73
 
76
74
  dispose() {
77
75
  if (!this.started) return;
78
- this.game.removeEventListener("roundEnd", this.onRoundEndBound);
76
+ this.game.removeEventListener("roundEnd", this.onRoundEnd);
79
77
  this.started = false;
80
78
  }
81
79
  clear() {