@firestone-hs/simulate-bgs-battle 1.1.757 → 1.1.759
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/battle-info-hash.d.ts +9 -0
- package/dist/battle-info-hash.js +39 -0
- package/dist/battle-info-hash.js.map +1 -0
- package/dist/cards/impl/minion/cthun.js +18 -15
- package/dist/cards/impl/minion/cthun.js.map +1 -1
- package/dist/simulate-bgs-battle.d.ts +1 -0
- package/dist/simulate-bgs-battle.js +9 -5
- package/dist/simulate-bgs-battle.js.map +1 -1
- package/dist/simulation/add-minion-to-board.js +12 -1
- package/dist/simulation/add-minion-to-board.js.map +1 -1
- package/dist/simulation/death-effects.js +8 -2
- package/dist/simulation/death-effects.js.map +1 -1
- package/dist/simulation/deity.d.ts +8 -0
- package/dist/simulation/deity.js +65 -3
- package/dist/simulation/deity.js.map +1 -1
- package/dist/simulation/spectator/game-action.d.ts +1 -0
- package/dist/simulation/spectator/game-action.js +24 -3
- package/dist/simulation/spectator/game-action.js.map +1 -1
- package/dist/simulation/spectator/spectator.js +2 -0
- package/dist/simulation/spectator/spectator.js.map +1 -1
- package/dist/simulation/start-of-combat/start-of-combat.js +3 -0
- package/dist/simulation/start-of-combat/start-of-combat.js.map +1 -1
- package/dist/simulation-result.d.ts +1 -0
- package/dist/simulation-result.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const hashBattleInfo: (battleInfo: BattleInfoHashInput | null | undefined) => string | null;
|
|
2
|
+
interface BattleInfoHashInput {
|
|
3
|
+
readonly playerBoard?: unknown;
|
|
4
|
+
readonly playerTeammateBoard?: unknown;
|
|
5
|
+
readonly opponentBoard?: unknown;
|
|
6
|
+
readonly opponentTeammateBoard?: unknown;
|
|
7
|
+
readonly gameState?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashBattleInfo = void 0;
|
|
4
|
+
const hashBattleInfo = (battleInfo) => {
|
|
5
|
+
var _a, _b, _c, _d, _e;
|
|
6
|
+
if (!battleInfo) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const payload = {
|
|
10
|
+
gameState: (_a = battleInfo.gameState) !== null && _a !== void 0 ? _a : null,
|
|
11
|
+
opponentBoard: (_b = battleInfo.opponentBoard) !== null && _b !== void 0 ? _b : null,
|
|
12
|
+
opponentTeammateBoard: (_c = battleInfo.opponentTeammateBoard) !== null && _c !== void 0 ? _c : null,
|
|
13
|
+
playerBoard: (_d = battleInfo.playerBoard) !== null && _d !== void 0 ? _d : null,
|
|
14
|
+
playerTeammateBoard: (_e = battleInfo.playerTeammateBoard) !== null && _e !== void 0 ? _e : null,
|
|
15
|
+
};
|
|
16
|
+
return fnv1a32(stableStringify(payload));
|
|
17
|
+
};
|
|
18
|
+
exports.hashBattleInfo = hashBattleInfo;
|
|
19
|
+
const stableStringify = (value) => {
|
|
20
|
+
var _a;
|
|
21
|
+
if (value === null || typeof value !== 'object') {
|
|
22
|
+
return (_a = JSON.stringify(value)) !== null && _a !== void 0 ? _a : 'null';
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return `[${value.map((entry) => stableStringify(entry)).join(',')}]`;
|
|
26
|
+
}
|
|
27
|
+
const record = value;
|
|
28
|
+
const keys = Object.keys(record).sort();
|
|
29
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(',')}}`;
|
|
30
|
+
};
|
|
31
|
+
const fnv1a32 = (text) => {
|
|
32
|
+
let hash = 0x811c9dc5;
|
|
33
|
+
for (let i = 0; i < text.length; i++) {
|
|
34
|
+
hash ^= text.charCodeAt(i);
|
|
35
|
+
hash = Math.imul(hash, 0x01000193);
|
|
36
|
+
}
|
|
37
|
+
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=battle-info-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"battle-info-hash.js","sourceRoot":"","sources":["../src/battle-info-hash.ts"],"names":[],"mappings":";;;AAKO,MAAM,cAAc,GAAG,CAAC,UAAkD,EAAiB,EAAE;;IACnG,IAAI,CAAC,UAAU,EAAE;QAChB,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,OAAO,GAAG;QACf,SAAS,EAAE,MAAA,UAAU,CAAC,SAAS,mCAAI,IAAI;QACvC,aAAa,EAAE,MAAA,UAAU,CAAC,aAAa,mCAAI,IAAI;QAC/C,qBAAqB,EAAE,MAAA,UAAU,CAAC,qBAAqB,mCAAI,IAAI;QAC/D,WAAW,EAAE,MAAA,UAAU,CAAC,WAAW,mCAAI,IAAI;QAC3C,mBAAmB,EAAE,MAAA,UAAU,CAAC,mBAAmB,mCAAI,IAAI;KAC3D,CAAC;IACF,OAAO,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC;AAZW,QAAA,cAAc,kBAYzB;AAUF,MAAM,eAAe,GAAG,CAAC,KAAc,EAAU,EAAE;;IAClD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAChD,OAAO,MAAA,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,mCAAI,MAAM,CAAC;KACvC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;KACrE;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACrG,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE;IACxC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACrC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;KACnC;IACD,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACnD,CAAC,CAAC","sourcesContent":["/**\r\n * Stable hash of the boards and game state that were simulated.\r\n * Excludes options and debugState: the feedback lambda rewrites options before resimulating.\r\n * Keep in sync with api-feedback/src/battle-info-hash.ts.\r\n */\r\nexport const hashBattleInfo = (battleInfo: BattleInfoHashInput | null | undefined): string | null => {\r\n\tif (!battleInfo) {\r\n\t\treturn null;\r\n\t}\r\n\tconst payload = {\r\n\t\tgameState: battleInfo.gameState ?? null,\r\n\t\topponentBoard: battleInfo.opponentBoard ?? null,\r\n\t\topponentTeammateBoard: battleInfo.opponentTeammateBoard ?? null,\r\n\t\tplayerBoard: battleInfo.playerBoard ?? null,\r\n\t\tplayerTeammateBoard: battleInfo.playerTeammateBoard ?? null,\r\n\t};\r\n\treturn fnv1a32(stableStringify(payload));\r\n};\r\n\r\ninterface BattleInfoHashInput {\r\n\treadonly playerBoard?: unknown;\r\n\treadonly playerTeammateBoard?: unknown;\r\n\treadonly opponentBoard?: unknown;\r\n\treadonly opponentTeammateBoard?: unknown;\r\n\treadonly gameState?: unknown;\r\n}\r\n\r\nconst stableStringify = (value: unknown): string => {\r\n\tif (value === null || typeof value !== 'object') {\r\n\t\treturn JSON.stringify(value) ?? 'null';\r\n\t}\r\n\tif (Array.isArray(value)) {\r\n\t\treturn `[${value.map((entry) => stableStringify(entry)).join(',')}]`;\r\n\t}\r\n\tconst record = value as Record<string, unknown>;\r\n\tconst keys = Object.keys(record).sort();\r\n\treturn `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(',')}}`;\r\n};\r\n\r\nconst fnv1a32 = (text: string): string => {\r\n\tlet hash = 0x811c9dc5;\r\n\tfor (let i = 0; i < text.length; i++) {\r\n\t\thash ^= text.charCodeAt(i);\r\n\t\thash = Math.imul(hash, 0x01000193);\r\n\t}\r\n\treturn (hash >>> 0).toString(16).padStart(8, '0');\r\n};\r\n"]}
|
|
@@ -6,27 +6,30 @@ const stats_1 = require("../../../simulation/stats");
|
|
|
6
6
|
exports.CThun = {
|
|
7
7
|
cardIds: ["BGFYM_000", "BGFYM_000_G"],
|
|
8
8
|
onAwaken: (minion, input) => {
|
|
9
|
-
var _a, _b
|
|
9
|
+
var _a, _b;
|
|
10
10
|
const others = input.board.filter((e) => e.entityId !== minion.entityId && e.health > 0 && !e.definitelyDead);
|
|
11
11
|
if (!others.length) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
const double = minion.cardId === "BGFYM_000_G" ? 2 : 1;
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
for (let i = 0; i < attack; i++) {
|
|
20
|
-
const target = (0, utils_1.pickRandom)(others, minion);
|
|
21
|
-
attackByEntity.set(target.entityId, ((_c = attackByEntity.get(target.entityId)) !== null && _c !== void 0 ? _c : 0) + 1);
|
|
22
|
-
}
|
|
23
|
-
for (let i = 0; i < health; i++) {
|
|
24
|
-
const target = (0, utils_1.pickRandom)(others, minion);
|
|
25
|
-
healthByEntity.set(target.entityId, ((_d = healthByEntity.get(target.entityId)) !== null && _d !== void 0 ? _d : 0) + 1);
|
|
26
|
-
}
|
|
27
|
-
for (const other of others) {
|
|
28
|
-
(0, stats_1.modifyStats)(other, minion, (_e = attackByEntity.get(other.entityId)) !== null && _e !== void 0 ? _e : 0, (_f = healthByEntity.get(other.entityId)) !== null && _f !== void 0 ? _f : 0, input.board, input.hero, input.gameState);
|
|
15
|
+
const attackShares = splitEvenly(((_a = minion.attack) !== null && _a !== void 0 ? _a : 0) * double, others, minion);
|
|
16
|
+
const healthShares = splitEvenly(((_b = minion.health) !== null && _b !== void 0 ? _b : 0) * double, others, minion);
|
|
17
|
+
for (let i = 0; i < others.length; i++) {
|
|
18
|
+
(0, stats_1.modifyStats)(others[i], minion, attackShares[i], healthShares[i], input.board, input.hero, input.gameState);
|
|
29
19
|
}
|
|
30
20
|
},
|
|
31
21
|
};
|
|
22
|
+
const splitEvenly = (total, targets, source) => {
|
|
23
|
+
const base = Math.floor(total / targets.length);
|
|
24
|
+
let remaining = total - base * targets.length;
|
|
25
|
+
const shares = targets.map(() => base);
|
|
26
|
+
const leftoverTargets = [...targets];
|
|
27
|
+
while (remaining > 0 && leftoverTargets.length) {
|
|
28
|
+
const target = (0, utils_1.pickRandom)(leftoverTargets, source);
|
|
29
|
+
shares[targets.indexOf(target)] += 1;
|
|
30
|
+
leftoverTargets.splice(leftoverTargets.indexOf(target), 1);
|
|
31
|
+
remaining--;
|
|
32
|
+
}
|
|
33
|
+
return shares;
|
|
34
|
+
};
|
|
32
35
|
//# sourceMappingURL=cthun.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cthun.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/cthun.ts"],"names":[],"mappings":";;;AAWA,mDAAqD;AACrD,qDAAwD;AAG3C,QAAA,KAAK,GAAc;IAC/B,OAAO,EAAE,4BAAoD;IAC7D,QAAQ,EAAE,CAAC,MAAmB,EAAE,KAAuB,EAAE,EAAE;;QAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QAC9G,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YACnB,OAAO;SACP;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,kBAA8B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,
|
|
1
|
+
{"version":3,"file":"cthun.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/cthun.ts"],"names":[],"mappings":";;;AAWA,mDAAqD;AACrD,qDAAwD;AAG3C,QAAA,KAAK,GAAc;IAC/B,OAAO,EAAE,4BAAoD;IAC7D,QAAQ,EAAE,CAAC,MAAmB,EAAE,KAAuB,EAAE,EAAE;;QAC1D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QAC9G,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YACnB,OAAO;SACP;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,kBAA8B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,MAAA,MAAM,CAAC,MAAM,mCAAI,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAChF,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,MAAA,MAAM,CAAC,MAAM,mCAAI,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAChF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACvC,IAAA,mBAAW,EAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;SAC3G;IACF,CAAC;CACD,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,OAAsB,EAAE,MAAmB,EAAY,EAAE;IAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,SAAS,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,eAAe,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;IACrC,OAAO,SAAS,GAAG,CAAC,IAAI,eAAe,CAAC,MAAM,EAAE;QAC/C,MAAM,MAAM,GAAG,IAAA,kBAAU,EAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,eAAe,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,SAAS,EAAE,CAAC;KACZ;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["/**\r\n * C'Thun (Tier 3, 1/1)\r\n * Deity. After this awakens, give this minion's stats split amongst your other minions.\r\n *\r\n * Golden C'Thun (Tier 3, 2/2)\r\n * Deity. After this awakens, give double this minion's stats split amongst your other minions.\r\n *\r\n * Only fires on BG_OldGod awaken, not generic spawn / reborn.\r\n */\r\nimport { BoardEntity } from '../../../board-entity';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { pickRandom } from '../../../services/utils';\r\nimport { modifyStats } from '../../../simulation/stats';\r\nimport { DeityAwakenInput, DeityCard } from '../../card.interface';\r\n\r\nexport const CThun: DeityCard = {\r\n\tcardIds: [CardIds.Cthun_BGFYM_000, CardIds.Cthun_BGFYM_000_G],\r\n\tonAwaken: (minion: BoardEntity, input: DeityAwakenInput) => {\r\n\t\tconst others = input.board.filter((e) => e.entityId !== minion.entityId && e.health > 0 && !e.definitelyDead);\r\n\t\tif (!others.length) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst double = minion.cardId === CardIds.Cthun_BGFYM_000_G ? 2 : 1;\r\n\t\tconst attackShares = splitEvenly((minion.attack ?? 0) * double, others, minion);\r\n\t\tconst healthShares = splitEvenly((minion.health ?? 0) * double, others, minion);\r\n\t\tfor (let i = 0; i < others.length; i++) {\r\n\t\t\tmodifyStats(others[i], minion, attackShares[i], healthShares[i], input.board, input.hero, input.gameState);\r\n\t\t}\r\n\t},\r\n};\r\n\r\nconst splitEvenly = (total: number, targets: BoardEntity[], source: BoardEntity): number[] => {\r\n\tconst base = Math.floor(total / targets.length);\r\n\tlet remaining = total - base * targets.length;\r\n\tconst shares = targets.map(() => base);\r\n\tconst leftoverTargets = [...targets];\r\n\twhile (remaining > 0 && leftoverTargets.length) {\r\n\t\tconst target = pickRandom(leftoverTargets, source);\r\n\t\tshares[targets.indexOf(target)] += 1;\r\n\t\tleftoverTargets.splice(leftoverTargets.indexOf(target), 1);\r\n\t\tremaining--;\r\n\t}\r\n\treturn shares;\r\n};\r\n"]}
|
|
@@ -14,6 +14,7 @@ export type { OnAttackInput } from './simulation/on-attack';
|
|
|
14
14
|
export { triggerBattlecry } from './simulation/battlecries';
|
|
15
15
|
export { doFullAttack } from './simulation/attack';
|
|
16
16
|
export { applyOnAttackEffects } from './simulation/on-attack';
|
|
17
|
+
export { hashBattleInfo } from './battle-info-hash';
|
|
17
18
|
export declare const SIMULATOR_VERSION: string;
|
|
18
19
|
export declare const ensureCardsLoaded: (cards?: AllCardsService) => Promise<boolean>;
|
|
19
20
|
export declare const assignCards: (cards: AllCardsService) => void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.simulateBattle = exports.simulateSingleCombat = exports.assignCards = exports.ensureCardsLoaded = exports.SIMULATOR_VERSION = exports.applyOnAttackEffects = exports.doFullAttack = exports.triggerBattlecry = exports.triggerRally = exports.hasRally = exports.isValidDeathrattleEnchantment = exports.withRng = exports.random = exports.getActiveRng = exports.defaultRng = exports.createSeededRng = void 0;
|
|
3
|
+
exports.simulateBattle = exports.simulateSingleCombat = exports.assignCards = exports.ensureCardsLoaded = exports.SIMULATOR_VERSION = exports.hashBattleInfo = exports.applyOnAttackEffects = exports.doFullAttack = exports.triggerBattlecry = exports.triggerRally = exports.hasRally = exports.isValidDeathrattleEnchantment = exports.withRng = exports.random = exports.getActiveRng = exports.defaultRng = exports.createSeededRng = void 0;
|
|
4
4
|
const reference_data_1 = require("@firestone-hs/reference-data");
|
|
5
|
+
const battle_info_hash_1 = require("./battle-info-hash");
|
|
5
6
|
const cards_data_1 = require("./cards/cards-data");
|
|
6
7
|
const debug_state_1 = require("./debug-state");
|
|
7
8
|
const input_clone_1 = require("./input-clone");
|
|
@@ -30,6 +31,8 @@ var attack_1 = require("./simulation/attack");
|
|
|
30
31
|
Object.defineProperty(exports, "doFullAttack", { enumerable: true, get: function () { return attack_1.doFullAttack; } });
|
|
31
32
|
var on_attack_1 = require("./simulation/on-attack");
|
|
32
33
|
Object.defineProperty(exports, "applyOnAttackEffects", { enumerable: true, get: function () { return on_attack_1.applyOnAttackEffects; } });
|
|
34
|
+
var battle_info_hash_2 = require("./battle-info-hash");
|
|
35
|
+
Object.defineProperty(exports, "hashBattleInfo", { enumerable: true, get: function () { return battle_info_hash_2.hashBattleInfo; } });
|
|
33
36
|
exports.SIMULATOR_VERSION = require('../package.json').version;
|
|
34
37
|
const MAX_SAMPLE_RESIMS = 500;
|
|
35
38
|
const CARDS_LOAD_ATTEMPTS = 3;
|
|
@@ -175,7 +178,7 @@ exports.default = async (event) => {
|
|
|
175
178
|
return response;
|
|
176
179
|
};
|
|
177
180
|
const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
178
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
181
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
179
182
|
if (!hasLoadedCards(cards)) {
|
|
180
183
|
console.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);
|
|
181
184
|
return null;
|
|
@@ -207,6 +210,7 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
207
210
|
averageDamageWon: undefined,
|
|
208
211
|
averageDamageLost: undefined,
|
|
209
212
|
simulatorVersion: exports.SIMULATOR_VERSION,
|
|
213
|
+
inputHash: (_l = (0, battle_info_hash_1.hashBattleInfo)(battleInput)) !== null && _l !== void 0 ? _l : undefined,
|
|
210
214
|
};
|
|
211
215
|
const spectator = new spectator_1.Spectator(includeOutcomeSamples);
|
|
212
216
|
const inputReady = (0, input_sanitation_1.buildFinalInput)(battleInput, cards, cardsData);
|
|
@@ -214,7 +218,7 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
214
218
|
const cloneTemplate = (0, input_clone_1.buildTemplateCloner)((0, input_clone_1.cloneInput3)(inputReady));
|
|
215
219
|
const runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng_1.defaultRng);
|
|
216
220
|
try {
|
|
217
|
-
!((
|
|
221
|
+
!((_m = battleInput.options) === null || _m === void 0 ? void 0 : _m.skipInfoLogs) && console.time('simulation');
|
|
218
222
|
const outcomes = {};
|
|
219
223
|
for (let i = 0; i < numberOfSimulations; i++) {
|
|
220
224
|
const battleResult = runOne();
|
|
@@ -233,7 +237,7 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
233
237
|
simulationResult.lost++;
|
|
234
238
|
simulationResult.damageLost += battleResult.damageDealt;
|
|
235
239
|
simulationResult.damageLosts.push(battleResult.damageDealt);
|
|
236
|
-
outcomes[battleResult.damageDealt] = ((
|
|
240
|
+
outcomes[battleResult.damageDealt] = ((_o = outcomes[battleResult.damageDealt]) !== null && _o !== void 0 ? _o : 0) + 1;
|
|
237
241
|
if (battleInput.playerBoard.player.hpLeft &&
|
|
238
242
|
battleResult.damageDealt >= battleInput.playerBoard.player.hpLeft) {
|
|
239
243
|
simulationResult.lostLethal++;
|
|
@@ -252,7 +256,7 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
updateSimulationResult(simulationResult, inputReady, damageConfidence);
|
|
255
|
-
!((
|
|
259
|
+
!((_p = battleInput.options) === null || _p === void 0 ? void 0 : _p.skipInfoLogs) && console.timeEnd('simulation');
|
|
256
260
|
if (includeOutcomeSamples) {
|
|
257
261
|
const neededOutcomes = [];
|
|
258
262
|
simulationResult.won > 0 && neededOutcomes.push('won');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { sleep } from './services/utils';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { combatProfileAdd, combatProfileEnabled, combatProfileTickFight } from './simulation/combat-profile';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { noopSpectator, Spectator } from './simulation/spectator/spectator';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\n\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\n/** Tavern Activate / Hand of Deios-style Rally triggers (requires a combat FullGameState). */\r\nexport { hasRally } from './cards/card.interface';\r\nexport type { RallyCard } from './cards/card.interface';\r\nexport { triggerRally } from './mechanics/rally';\r\nexport type { OnAttackInput } from './simulation/on-attack';\r\n/** Tavern / Hand of Deios-style Battlecry re-triggers. */\r\nexport { triggerBattlecry } from './simulation/battlecries';\r\n/** Full attack resolution (on-attack, damage, after-attack, deaths) for tavern attacks e.g. Fishbait. */\r\nexport { doFullAttack } from './simulation/attack';\r\nexport { applyOnAttackEffects } from './simulation/on-attack';\r\n\r\n/** Inlined from package.json when this module is bundled. A stale window keeps the old value. */\r\n// eslint-disable-next-line @typescript-eslint/no-var-requires\r\nexport const SIMULATOR_VERSION: string = require('../package.json').version;\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\nconst CARDS_LOAD_ATTEMPTS = 3;\r\n\r\nlet globalCards = new AllCardsService();\r\n/** In-flight / completed cards init for this warm container (avoids re-fetch per invoke). */\r\nlet cardsInitPromise: Promise<boolean> | null = null;\r\n\r\n/** `getCards()` materializes the full DB (~14ms). Validate once per instance. */\r\nconst verifiedCardDbs = new WeakSet<object>();\r\n\r\nconst hasLoadedCards = (cards: AllCardsService | null | undefined): boolean => {\r\n\tif (!cards) {\r\n\t\treturn false;\r\n\t}\r\n\tif (verifiedCardDbs.has(cards as object)) {\r\n\t\treturn true;\r\n\t}\r\n\t// Prefer a single-card lookup. getCards() copies the whole DB (~14ms).\r\n\tconst probe = cards.getCard?.('CS2_122');\r\n\tif (probe?.id) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t\treturn true;\r\n\t}\r\n\tconst loaded = !!cards.getCards?.()?.length;\r\n\tif (loaded) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t}\r\n\treturn loaded;\r\n};\r\n\r\nconst loadCardsWithRetry = async (cards: AllCardsService): Promise<boolean> => {\r\n\tfor (let attempt = 1; attempt <= CARDS_LOAD_ATTEMPTS; attempt++) {\r\n\t\ttry {\r\n\t\t\tawait cards.initializeCardsDb();\r\n\t\t\tif (hasLoadedCards(cards)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards still empty after initializeCardsDb', attempt);\r\n\t\t} catch (e) {\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards load attempt failed', attempt, e);\r\n\t\t}\r\n\t\tif (attempt < CARDS_LOAD_ATTEMPTS) {\r\n\t\t\tawait sleep(250 * attempt);\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\n/**\r\n * Load reference cards once per warm container. Retries transient CDN/fetch failures.\r\n * Returns false when cards could not be loaded after retries.\r\n */\r\nexport const ensureCardsLoaded = async (cards: AllCardsService = globalCards): Promise<boolean> => {\r\n\tif (hasLoadedCards(cards)) {\r\n\t\treturn true;\r\n\t}\r\n\tif (!cardsInitPromise) {\r\n\t\tcardsInitPromise = loadCardsWithRetry(cards).then((ok) => {\r\n\t\t\tif (!ok) {\r\n\t\t\t\t// Allow the next invoke to retry after a hard failure.\r\n\t\t\t\tcardsInitPromise = null;\r\n\t\t\t}\r\n\t\t\treturn ok;\r\n\t\t});\r\n\t}\r\n\treturn cardsInitPromise;\r\n};\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n\tcardsInitPromise = hasLoadedCards(cards) ? Promise.resolve(true) : null;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tconst profile = combatProfileEnabled();\r\n\tconst getCardsT0 = profile ? performance.now() : 0;\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\tif (profile) {\r\n\t\tcombatProfileAdd('getCardsMs', performance.now() - getCardsT0);\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst buildT0 = profile ? performance.now() : 0;\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('buildFinalInputMs', performance.now() - buildT0);\r\n\t\t}\r\n\t\t// One fight: cloneInput3 per use (battle + optional initial-state snapshot).\r\n\t\t// Firestone Monte Carlo keeps buildTemplateCloner for 8000 sims.\r\n\t\tconst cloneTemplate = () => {\r\n\t\t\tconst cloneT0 = profile ? performance.now() : 0;\r\n\t\t\tconst cloned = cloneInput3(inputReady);\r\n\t\t\tif (profile) {\r\n\t\t\t\tcombatProfileAdd('cloneMs', performance.now() - cloneT0);\r\n\t\t\t}\r\n\t\t\treturn cloned;\r\n\t\t};\r\n\t\tconst spectator = includeSpectator ? new Spectator(true) : noopSpectator;\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\tconst runT0 = profile ? performance.now() : 0;\r\n\t\tconst result = withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('runBattleMs', performance.now() - runT0);\r\n\t\t\tcombatProfileTickFight();\r\n\t\t}\r\n\t\treturn result;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn {\r\n\t\t\tstatusCode: 400,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: null,\r\n\t\t};\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tconst cardsLoaded = await ensureCardsLoaded(cards);\r\n\tif (!cardsLoaded) {\r\n\t\tconsole.error('[simulate-bgs-battle] failed to load reference cards after retries');\r\n\t\treturn {\r\n\t\t\tstatusCode: 503,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: JSON.stringify({ error: 'cards_unavailable' }),\r\n\t\t};\r\n\t}\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t\tsimulatorVersion: SIMULATOR_VERSION,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tisDuos: !!input.playerTeammateBoard || !!input.opponentTeammateBoard,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase =\r\n\t\tbattleInput.debugState.forcedFaceOffBase?.map((f) => ({\r\n\t\t\tattacker: { ...f.attacker },\r\n\t\t\tdefender: { ...f.defender },\r\n\t\t})) ?? [];\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
|
|
1
|
+
{"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { hashBattleInfo } from './battle-info-hash';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { sleep } from './services/utils';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { combatProfileAdd, combatProfileEnabled, combatProfileTickFight } from './simulation/combat-profile';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { noopSpectator, Spectator } from './simulation/spectator/spectator';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\n\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\n/** Tavern Activate / Hand of Deios-style Rally triggers (requires a combat FullGameState). */\r\nexport { hasRally } from './cards/card.interface';\r\nexport type { RallyCard } from './cards/card.interface';\r\nexport { triggerRally } from './mechanics/rally';\r\nexport type { OnAttackInput } from './simulation/on-attack';\r\n/** Tavern / Hand of Deios-style Battlecry re-triggers. */\r\nexport { triggerBattlecry } from './simulation/battlecries';\r\n/** Full attack resolution (on-attack, damage, after-attack, deaths) for tavern attacks e.g. Fishbait. */\r\nexport { doFullAttack } from './simulation/attack';\r\nexport { applyOnAttackEffects } from './simulation/on-attack';\r\nexport { hashBattleInfo } from './battle-info-hash';\r\n\r\n/** Inlined from package.json when this module is bundled. A stale window keeps the old value. */\r\n// eslint-disable-next-line @typescript-eslint/no-var-requires\r\nexport const SIMULATOR_VERSION: string = require('../package.json').version;\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\nconst CARDS_LOAD_ATTEMPTS = 3;\r\n\r\nlet globalCards = new AllCardsService();\r\n/** In-flight / completed cards init for this warm container (avoids re-fetch per invoke). */\r\nlet cardsInitPromise: Promise<boolean> | null = null;\r\n\r\n/** `getCards()` materializes the full DB (~14ms). Validate once per instance. */\r\nconst verifiedCardDbs = new WeakSet<object>();\r\n\r\nconst hasLoadedCards = (cards: AllCardsService | null | undefined): boolean => {\r\n\tif (!cards) {\r\n\t\treturn false;\r\n\t}\r\n\tif (verifiedCardDbs.has(cards as object)) {\r\n\t\treturn true;\r\n\t}\r\n\t// Prefer a single-card lookup. getCards() copies the whole DB (~14ms).\r\n\tconst probe = cards.getCard?.('CS2_122');\r\n\tif (probe?.id) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t\treturn true;\r\n\t}\r\n\tconst loaded = !!cards.getCards?.()?.length;\r\n\tif (loaded) {\r\n\t\tverifiedCardDbs.add(cards as object);\r\n\t}\r\n\treturn loaded;\r\n};\r\n\r\nconst loadCardsWithRetry = async (cards: AllCardsService): Promise<boolean> => {\r\n\tfor (let attempt = 1; attempt <= CARDS_LOAD_ATTEMPTS; attempt++) {\r\n\t\ttry {\r\n\t\t\tawait cards.initializeCardsDb();\r\n\t\t\tif (hasLoadedCards(cards)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards still empty after initializeCardsDb', attempt);\r\n\t\t} catch (e) {\r\n\t\t\tconsole.warn('[simulate-bgs-battle] cards load attempt failed', attempt, e);\r\n\t\t}\r\n\t\tif (attempt < CARDS_LOAD_ATTEMPTS) {\r\n\t\t\tawait sleep(250 * attempt);\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\n/**\r\n * Load reference cards once per warm container. Retries transient CDN/fetch failures.\r\n * Returns false when cards could not be loaded after retries.\r\n */\r\nexport const ensureCardsLoaded = async (cards: AllCardsService = globalCards): Promise<boolean> => {\r\n\tif (hasLoadedCards(cards)) {\r\n\t\treturn true;\r\n\t}\r\n\tif (!cardsInitPromise) {\r\n\t\tcardsInitPromise = loadCardsWithRetry(cards).then((ok) => {\r\n\t\t\tif (!ok) {\r\n\t\t\t\t// Allow the next invoke to retry after a hard failure.\r\n\t\t\t\tcardsInitPromise = null;\r\n\t\t\t}\r\n\t\t\treturn ok;\r\n\t\t});\r\n\t}\r\n\treturn cardsInitPromise;\r\n};\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n\tcardsInitPromise = hasLoadedCards(cards) ? Promise.resolve(true) : null;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tconst profile = combatProfileEnabled();\r\n\tconst getCardsT0 = profile ? performance.now() : 0;\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\tif (profile) {\r\n\t\tcombatProfileAdd('getCardsMs', performance.now() - getCardsT0);\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst buildT0 = profile ? performance.now() : 0;\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('buildFinalInputMs', performance.now() - buildT0);\r\n\t\t}\r\n\t\t// One fight: cloneInput3 per use (battle + optional initial-state snapshot).\r\n\t\t// Firestone Monte Carlo keeps buildTemplateCloner for 8000 sims.\r\n\t\tconst cloneTemplate = () => {\r\n\t\t\tconst cloneT0 = profile ? performance.now() : 0;\r\n\t\t\tconst cloned = cloneInput3(inputReady);\r\n\t\t\tif (profile) {\r\n\t\t\t\tcombatProfileAdd('cloneMs', performance.now() - cloneT0);\r\n\t\t\t}\r\n\t\t\treturn cloned;\r\n\t\t};\r\n\t\tconst spectator = includeSpectator ? new Spectator(true) : noopSpectator;\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\tconst runT0 = profile ? performance.now() : 0;\r\n\t\tconst result = withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t\tif (profile) {\r\n\t\t\tcombatProfileAdd('runBattleMs', performance.now() - runT0);\r\n\t\t\tcombatProfileTickFight();\r\n\t\t}\r\n\t\treturn result;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn {\r\n\t\t\tstatusCode: 400,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: null,\r\n\t\t};\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tconst cardsLoaded = await ensureCardsLoaded(cards);\r\n\tif (!cardsLoaded) {\r\n\t\tconsole.error('[simulate-bgs-battle] failed to load reference cards after retries');\r\n\t\treturn {\r\n\t\t\tstatusCode: 503,\r\n\t\t\tisBase64Encoded: false,\r\n\t\t\tbody: JSON.stringify({ error: 'cards_unavailable' }),\r\n\t\t};\r\n\t}\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!hasLoadedCards(cards)) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t\tsimulatorVersion: SIMULATOR_VERSION,\r\n\t\tinputHash: hashBattleInfo(battleInput) ?? undefined,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tisDuos: !!input.playerTeammateBoard || !!input.opponentTeammateBoard,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase =\r\n\t\tbattleInput.debugState.forcedFaceOffBase?.map((f) => ({\r\n\t\t\tattacker: { ...f.attacker },\r\n\t\t\tdefender: { ...f.defender },\r\n\t\t})) ?? [];\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
|
|
@@ -10,6 +10,7 @@ const divine_shield_1 = require("../keywords/divine-shield");
|
|
|
10
10
|
const taunt_1 = require("../keywords/taunt");
|
|
11
11
|
const utils_1 = require("../services/utils");
|
|
12
12
|
const utils_2 = require("../utils");
|
|
13
|
+
const deity_1 = require("./deity");
|
|
13
14
|
const quest_1 = require("./quest");
|
|
14
15
|
const stats_1 = require("./stats");
|
|
15
16
|
const addMinionToBoard = (board, boardHero, otherBoard, otherHero, index, minionToAdd, gameState, applySelfAuras = true) => {
|
|
@@ -162,7 +163,7 @@ const handleAddedMinionAuraEffect = (board, boardHero, otherBoard, otherHero, sp
|
|
|
162
163
|
};
|
|
163
164
|
exports.handleAddedMinionAuraEffect = handleAddedMinionAuraEffect;
|
|
164
165
|
const applyAurasToSelf = (spawned, board, boardHero, gameState, applyAttackAuras = true, applyHealthAuras = true) => {
|
|
165
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
166
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
166
167
|
if (applyAttackAuras) {
|
|
167
168
|
spawned.attack += boardHero.globalInfo.AdditionalAttack;
|
|
168
169
|
}
|
|
@@ -409,6 +410,16 @@ const applyAurasToSelf = (spawned, board, boardHero, gameState, applyAttackAuras
|
|
|
409
410
|
(0, stats_1.modifyStats)(spawned, null, applyAttackAuras ? statsBonusGnoll : 0, applyHealthAuras ? 0 : 0, board, boardHero, gameState, false);
|
|
410
411
|
break;
|
|
411
412
|
}
|
|
413
|
+
if ((0, deity_1.isDeityCard)(spawned.cardId, gameState.allCards) && !(0, deity_1.consumeDeityBaseStatsAssignment)(spawned)) {
|
|
414
|
+
const { attack, health } = (0, deity_1.getDeityAuraSnapshot)(spawned, boardHero);
|
|
415
|
+
const card = gameState.allCards.getCard(spawned.cardId);
|
|
416
|
+
const auraAttack = Math.max(0, attack - ((_k = card === null || card === void 0 ? void 0 : card.attack) !== null && _k !== void 0 ? _k : 0));
|
|
417
|
+
const auraHealth = Math.max(0, health - ((_l = card === null || card === void 0 ? void 0 : card.health) !== null && _l !== void 0 ? _l : 0));
|
|
418
|
+
spawned.tags = (_m = spawned.tags) !== null && _m !== void 0 ? _m : {};
|
|
419
|
+
spawned.tags[reference_data_1.GameTag.BACON_OLD_GOD_ATTACK] = attack;
|
|
420
|
+
spawned.tags[reference_data_1.GameTag.BACON_OLD_GOD_HEALTH] = health;
|
|
421
|
+
(0, stats_1.modifyStats)(spawned, null, applyAttackAuras ? auraAttack : 0, applyHealthAuras ? auraHealth : 0, board, boardHero, gameState, false);
|
|
422
|
+
}
|
|
412
423
|
};
|
|
413
424
|
exports.applyAurasToSelf = applyAurasToSelf;
|
|
414
425
|
const removeAurasFromSelf = (entity, board, boardHero, gameState, applyAttackAuras = true, applyHealthAuras = true, isOnBoard = true) => {
|