labag 2.3.3 → 2.3.4
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/index.d.ts +6 -1
- package/dist/index.js +9 -1
- package/dist/recordChecker.d.ts +18 -0
- package/dist/recordChecker.js +70 -0
- package/dist/recorder.d.ts +29 -0
- package/dist/recorder.js +77 -0
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/recordChecker.ts +84 -0
- package/src/recorder.ts +95 -0
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,10 @@ import { LaBaG } from "./labag";
|
|
|
2
2
|
import { modeList, ModeName } from "./modes";
|
|
3
3
|
import { LaBaGEvent, Pattern, PatternName } from "./types";
|
|
4
4
|
import { Mode } from "./mode";
|
|
5
|
+
import { patterns } from "./pattern";
|
|
6
|
+
import { Recorder, GameRecord } from './recorder';
|
|
7
|
+
import { RecordChecker } from "./recordChecker";
|
|
5
8
|
declare const labag: LaBaG;
|
|
6
|
-
|
|
9
|
+
declare const recorder: Recorder;
|
|
10
|
+
declare const checker: RecordChecker;
|
|
11
|
+
export { labag, recorder, checker, modeList, patterns, LaBaG, Mode, type LaBaGEvent, type Pattern, type PatternName, type ModeName, type GameRecord };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Mode = exports.LaBaG = exports.modeList = exports.labag = void 0;
|
|
3
|
+
exports.Mode = exports.LaBaG = exports.patterns = exports.modeList = exports.checker = exports.recorder = exports.labag = void 0;
|
|
4
4
|
const labag_1 = require("./labag");
|
|
5
5
|
Object.defineProperty(exports, "LaBaG", { enumerable: true, get: function () { return labag_1.LaBaG; } });
|
|
6
6
|
const modes_1 = require("./modes");
|
|
7
7
|
Object.defineProperty(exports, "modeList", { enumerable: true, get: function () { return modes_1.modeList; } });
|
|
8
8
|
const mode_1 = require("./mode");
|
|
9
9
|
Object.defineProperty(exports, "Mode", { enumerable: true, get: function () { return mode_1.Mode; } });
|
|
10
|
+
const pattern_1 = require("./pattern");
|
|
11
|
+
Object.defineProperty(exports, "patterns", { enumerable: true, get: function () { return pattern_1.patterns; } });
|
|
12
|
+
const recorder_1 = require("./recorder");
|
|
13
|
+
const recordChecker_1 = require("./recordChecker");
|
|
10
14
|
const labag = new labag_1.LaBaG();
|
|
11
15
|
exports.labag = labag;
|
|
12
16
|
modes_1.modeList.forEach((mode) => {
|
|
13
17
|
labag.addMode(mode);
|
|
14
18
|
});
|
|
19
|
+
const recorder = new recorder_1.Recorder(labag);
|
|
20
|
+
exports.recorder = recorder;
|
|
21
|
+
const checker = new recordChecker_1.RecordChecker(labag);
|
|
22
|
+
exports.checker = checker;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { LaBaG } from "./labag";
|
|
2
|
+
import { GameRecord } from "./recorder";
|
|
3
|
+
export declare class RecordChecker {
|
|
4
|
+
private game;
|
|
5
|
+
constructor(game: LaBaG);
|
|
6
|
+
/**
|
|
7
|
+
* 驗證紀錄的分數是否正確。
|
|
8
|
+
* @param record - 要驗證的遊戲紀錄。
|
|
9
|
+
* @returns 如果計算出的分數與紀錄中的分數一致則返回 true,否則返回 false。
|
|
10
|
+
*/
|
|
11
|
+
check(record: GameRecord): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 根據紀錄還原並計算分數。
|
|
14
|
+
* @param record - 遊戲紀錄。
|
|
15
|
+
* @returns 計算出的分數。
|
|
16
|
+
*/
|
|
17
|
+
calculateScore(record: GameRecord): number;
|
|
18
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecordChecker = void 0;
|
|
4
|
+
class RecordChecker {
|
|
5
|
+
game;
|
|
6
|
+
constructor(game) {
|
|
7
|
+
this.game = game;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 驗證紀錄的分數是否正確。
|
|
11
|
+
* @param record - 要驗證的遊戲紀錄。
|
|
12
|
+
* @returns 如果計算出的分數與紀錄中的分數一致則返回 true,否則返回 false。
|
|
13
|
+
*/
|
|
14
|
+
check(record) {
|
|
15
|
+
const calculatedScore = this.calculateScore(record);
|
|
16
|
+
return calculatedScore === record.score;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 根據紀錄還原並計算分數。
|
|
20
|
+
* @param record - 遊戲紀錄。
|
|
21
|
+
* @returns 計算出的分數。
|
|
22
|
+
*/
|
|
23
|
+
calculateScore(record) {
|
|
24
|
+
// 重置遊戲狀態
|
|
25
|
+
this.game.init();
|
|
26
|
+
this.game.times = record.times;
|
|
27
|
+
// 使用 any 類型來存取私有方法
|
|
28
|
+
const gameAny = this.game;
|
|
29
|
+
for (const round of record.rounds) {
|
|
30
|
+
if (!this.game.isRunning()) {
|
|
31
|
+
throw new Error("遊戲次數已達上限,無法繼續遊玩。");
|
|
32
|
+
}
|
|
33
|
+
// 1. 回合開始
|
|
34
|
+
gameAny.roundStart();
|
|
35
|
+
// 2. 設定隨機數字與圖案 (模擬 rollSlots)
|
|
36
|
+
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) => {
|
|
43
|
+
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
|
+
});
|
|
51
|
+
// 觸發 rollSlots 事件,讓模式執行其邏輯 (例如 greenwei 產生隨機數)
|
|
52
|
+
gameAny.emit("rollSlots");
|
|
53
|
+
// 3. 覆蓋模式的隨機變數 (確保使用紀錄中的數值)
|
|
54
|
+
this.game.modes.forEach((mode) => {
|
|
55
|
+
if (round.randNums[mode.name] !== undefined) {
|
|
56
|
+
mode.variable.randNum = round.randNums[mode.name];
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// 4. 計算分數
|
|
60
|
+
gameAny.calculateScore();
|
|
61
|
+
// 5. 回合結束
|
|
62
|
+
gameAny.roundEnd();
|
|
63
|
+
}
|
|
64
|
+
if (!this.game.isRunning()) {
|
|
65
|
+
gameAny.gameOver();
|
|
66
|
+
}
|
|
67
|
+
return this.game.score;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.RecordChecker = RecordChecker;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { LaBaG } from "./labag";
|
|
2
|
+
export type RoundRecord = {
|
|
3
|
+
randNums: Record<string, number>;
|
|
4
|
+
};
|
|
5
|
+
export type GameRecord = {
|
|
6
|
+
times: number;
|
|
7
|
+
score: number;
|
|
8
|
+
rounds: RoundRecord[];
|
|
9
|
+
};
|
|
10
|
+
export type RecorderOptions = {
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare class Recorder {
|
|
14
|
+
#private;
|
|
15
|
+
private game;
|
|
16
|
+
private score;
|
|
17
|
+
private onRoundEndBound;
|
|
18
|
+
private started;
|
|
19
|
+
private debug;
|
|
20
|
+
constructor(gameInstance: LaBaG, options?: RecorderOptions);
|
|
21
|
+
get rounds(): {
|
|
22
|
+
randNums: Record<string, number>;
|
|
23
|
+
}[];
|
|
24
|
+
private onRoundEnd;
|
|
25
|
+
init(clearExisting?: boolean): void;
|
|
26
|
+
dispose(): void;
|
|
27
|
+
clear(): void;
|
|
28
|
+
getRecord(): GameRecord;
|
|
29
|
+
}
|
package/dist/recorder.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Recorder = void 0;
|
|
4
|
+
class Recorder {
|
|
5
|
+
game;
|
|
6
|
+
#rounds = [];
|
|
7
|
+
score = 0;
|
|
8
|
+
onRoundEndBound;
|
|
9
|
+
started = false;
|
|
10
|
+
debug = false;
|
|
11
|
+
constructor(gameInstance, options) {
|
|
12
|
+
this.game = gameInstance;
|
|
13
|
+
this.onRoundEndBound = this.onRoundEnd.bind(this);
|
|
14
|
+
this.debug = !!options?.debug;
|
|
15
|
+
}
|
|
16
|
+
get rounds() {
|
|
17
|
+
return this.#rounds.map((r) => ({ ...r }));
|
|
18
|
+
}
|
|
19
|
+
onRoundEnd(g) {
|
|
20
|
+
const randNums = {};
|
|
21
|
+
g.randNums.forEach((value, key) => {
|
|
22
|
+
if (!isNaN(value)) {
|
|
23
|
+
randNums[key] = value;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
// 收集各模式的 randNum(若為數值且有效)
|
|
27
|
+
g.modes.forEach((mode) => {
|
|
28
|
+
const rn = mode?.variable?.randNum;
|
|
29
|
+
if (!isNaN(rn)) {
|
|
30
|
+
randNums[mode.name] = rn;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const round = {
|
|
34
|
+
randNums,
|
|
35
|
+
};
|
|
36
|
+
if (this.debug)
|
|
37
|
+
console.debug("recorder:onRoundEnd", {
|
|
38
|
+
round,
|
|
39
|
+
score: g.score,
|
|
40
|
+
});
|
|
41
|
+
this.#rounds.push(round);
|
|
42
|
+
this.score = g.score;
|
|
43
|
+
}
|
|
44
|
+
init(clearExisting = true) {
|
|
45
|
+
if (this.started)
|
|
46
|
+
return;
|
|
47
|
+
if (clearExisting) {
|
|
48
|
+
this.clear();
|
|
49
|
+
}
|
|
50
|
+
if (typeof this.game.addEventListener === "function") {
|
|
51
|
+
this.game.addEventListener("roundEnd", this.onRoundEndBound);
|
|
52
|
+
this.started = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
dispose() {
|
|
56
|
+
if (!this.started)
|
|
57
|
+
return;
|
|
58
|
+
this.game.removeEventListener("roundEnd", this.onRoundEndBound);
|
|
59
|
+
this.started = false;
|
|
60
|
+
}
|
|
61
|
+
clear() {
|
|
62
|
+
if (this.debug)
|
|
63
|
+
console.debug("clear");
|
|
64
|
+
this.score = 0;
|
|
65
|
+
this.#rounds = [];
|
|
66
|
+
}
|
|
67
|
+
getRecord() {
|
|
68
|
+
if (this.debug)
|
|
69
|
+
console.debug("get");
|
|
70
|
+
return {
|
|
71
|
+
times: this.game.times,
|
|
72
|
+
score: this.score,
|
|
73
|
+
rounds: this.#rounds,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.Recorder = Recorder;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,18 +2,27 @@ import { LaBaG } from "./labag";
|
|
|
2
2
|
import { modeList, ModeName } from "./modes";
|
|
3
3
|
import { LaBaGEvent, Pattern, PatternName } from "./types";
|
|
4
4
|
import { Mode } from "./mode";
|
|
5
|
+
import { patterns } from "./pattern";
|
|
6
|
+
import { Recorder, GameRecord } from './recorder';
|
|
7
|
+
import { RecordChecker } from "./recordChecker";
|
|
5
8
|
|
|
6
9
|
const labag = new LaBaG();
|
|
7
10
|
modeList.forEach((mode) => {
|
|
8
11
|
labag.addMode(mode);
|
|
9
12
|
});
|
|
13
|
+
const recorder = new Recorder(labag);
|
|
14
|
+
const checker = new RecordChecker(labag);
|
|
10
15
|
export {
|
|
11
16
|
labag,
|
|
17
|
+
recorder,
|
|
18
|
+
checker,
|
|
12
19
|
modeList,
|
|
20
|
+
patterns,
|
|
13
21
|
LaBaG,
|
|
14
22
|
Mode,
|
|
15
23
|
type LaBaGEvent,
|
|
16
24
|
type Pattern,
|
|
17
25
|
type PatternName,
|
|
18
26
|
type ModeName,
|
|
27
|
+
type GameRecord
|
|
19
28
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { LaBaG } from "./labag";
|
|
2
|
+
import { GameRecord } from "./recorder";
|
|
3
|
+
|
|
4
|
+
export class RecordChecker {
|
|
5
|
+
private game: LaBaG;
|
|
6
|
+
|
|
7
|
+
constructor(game: LaBaG) {
|
|
8
|
+
this.game = game;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 驗證紀錄的分數是否正確。
|
|
13
|
+
* @param record - 要驗證的遊戲紀錄。
|
|
14
|
+
* @returns 如果計算出的分數與紀錄中的分數一致則返回 true,否則返回 false。
|
|
15
|
+
*/
|
|
16
|
+
check(record: GameRecord): boolean {
|
|
17
|
+
const calculatedScore = this.calculateScore(record);
|
|
18
|
+
return calculatedScore === record.score;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 根據紀錄還原並計算分數。
|
|
23
|
+
* @param record - 遊戲紀錄。
|
|
24
|
+
* @returns 計算出的分數。
|
|
25
|
+
*/
|
|
26
|
+
calculateScore(record: GameRecord): number {
|
|
27
|
+
// 重置遊戲狀態
|
|
28
|
+
this.game.init();
|
|
29
|
+
this.game.times = record.times;
|
|
30
|
+
|
|
31
|
+
// 使用 any 類型來存取私有方法
|
|
32
|
+
const gameAny = this.game as any;
|
|
33
|
+
|
|
34
|
+
for (const round of record.rounds) {
|
|
35
|
+
if (!this.game.isRunning()) {
|
|
36
|
+
throw new Error("遊戲次數已達上限,無法繼續遊玩。");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 1. 回合開始
|
|
40
|
+
gameAny.roundStart();
|
|
41
|
+
|
|
42
|
+
// 2. 設定隨機數字與圖案 (模擬 rollSlots)
|
|
43
|
+
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) => {
|
|
52
|
+
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
|
+
});
|
|
59
|
+
|
|
60
|
+
// 觸發 rollSlots 事件,讓模式執行其邏輯 (例如 greenwei 產生隨機數)
|
|
61
|
+
gameAny.emit("rollSlots");
|
|
62
|
+
|
|
63
|
+
// 3. 覆蓋模式的隨機變數 (確保使用紀錄中的數值)
|
|
64
|
+
this.game.modes.forEach((mode) => {
|
|
65
|
+
if (round.randNums[mode.name] !== undefined) {
|
|
66
|
+
mode.variable.randNum = round.randNums[mode.name];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// 4. 計算分數
|
|
71
|
+
gameAny.calculateScore();
|
|
72
|
+
|
|
73
|
+
// 5. 回合結束
|
|
74
|
+
gameAny.roundEnd();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!this.game.isRunning()) {
|
|
78
|
+
gameAny.gameOver();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return this.game.score;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
package/src/recorder.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { LaBaG } from "./labag";
|
|
2
|
+
|
|
3
|
+
export type RoundRecord = {
|
|
4
|
+
randNums: Record<string, number>;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type GameRecord = {
|
|
8
|
+
times: number;
|
|
9
|
+
score: number;
|
|
10
|
+
rounds: RoundRecord[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type RecorderOptions = {
|
|
14
|
+
debug?: boolean; // 若為 true,會以 console.debug 輸出紀錄
|
|
15
|
+
};
|
|
16
|
+
export class Recorder {
|
|
17
|
+
private game: LaBaG;
|
|
18
|
+
#rounds: RoundRecord[] = [];
|
|
19
|
+
private score: number = 0;
|
|
20
|
+
private onRoundEndBound: (e: LaBaG) => void;
|
|
21
|
+
private started = false;
|
|
22
|
+
private debug = false;
|
|
23
|
+
|
|
24
|
+
constructor(gameInstance: LaBaG, options?: RecorderOptions) {
|
|
25
|
+
this.game = gameInstance;
|
|
26
|
+
this.onRoundEndBound = this.onRoundEnd.bind(this);
|
|
27
|
+
this.debug = !!options?.debug;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get rounds() {
|
|
31
|
+
return this.#rounds.map((r) => ({ ...r }));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private onRoundEnd(g: LaBaG) {
|
|
35
|
+
const randNums: Record<string, number> = {};
|
|
36
|
+
|
|
37
|
+
g.randNums.forEach((value, key) => {
|
|
38
|
+
if (!isNaN(value)) {
|
|
39
|
+
randNums[key] = value;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 收集各模式的 randNum(若為數值且有效)
|
|
44
|
+
g.modes.forEach((mode) => {
|
|
45
|
+
const rn = mode?.variable?.randNum;
|
|
46
|
+
if (!isNaN(rn)) {
|
|
47
|
+
randNums[mode.name] = rn;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const round: RoundRecord = {
|
|
52
|
+
randNums,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (this.debug)
|
|
56
|
+
console.debug("recorder:onRoundEnd", {
|
|
57
|
+
round,
|
|
58
|
+
score: g.score,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.#rounds.push(round);
|
|
62
|
+
this.score = g.score;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
init(clearExisting = true) {
|
|
66
|
+
if (this.started) return;
|
|
67
|
+
if (clearExisting) {
|
|
68
|
+
this.clear();
|
|
69
|
+
}
|
|
70
|
+
if (typeof this.game.addEventListener === "function") {
|
|
71
|
+
this.game.addEventListener("roundEnd", this.onRoundEndBound);
|
|
72
|
+
this.started = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
dispose() {
|
|
77
|
+
if (!this.started) return;
|
|
78
|
+
this.game.removeEventListener("roundEnd", this.onRoundEndBound);
|
|
79
|
+
this.started = false;
|
|
80
|
+
}
|
|
81
|
+
clear() {
|
|
82
|
+
if (this.debug) console.debug("clear");
|
|
83
|
+
this.score = 0;
|
|
84
|
+
this.#rounds = [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getRecord(): GameRecord {
|
|
88
|
+
if (this.debug) console.debug("get");
|
|
89
|
+
return {
|
|
90
|
+
times: this.game.times,
|
|
91
|
+
score: this.score,
|
|
92
|
+
rounds: this.#rounds,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|