@firestone-hs/simulate-bgs-battle 1.1.691 → 1.1.692
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/bgs-battle-info.d.ts +19 -0
- package/dist/bgs-battle-info.js.map +1 -1
- package/dist/cards/impl/minion/photobomber.js +1 -1
- package/dist/cards/impl/minion/photobomber.js.map +1 -1
- package/dist/cards/impl/minion/timewarped-embalmer.d.ts +2 -2
- package/dist/cards/impl/minion/timewarped-embalmer.js +7 -0
- package/dist/cards/impl/minion/timewarped-embalmer.js.map +1 -1
- package/dist/cards/impl/minion/timewarped-warghoul.js +8 -3
- package/dist/cards/impl/minion/timewarped-warghoul.js.map +1 -1
- package/dist/debug-state.d.ts +8 -0
- package/dist/debug-state.js +11 -3
- package/dist/debug-state.js.map +1 -1
- package/dist/services/utils.d.ts +2 -1
- package/dist/services/utils.js +25 -9
- package/dist/services/utils.js.map +1 -1
- package/dist/simulate-bgs-battle.js +98 -74
- package/dist/simulate-bgs-battle.js.map +1 -1
- package/dist/simulation/secrets.js +6 -2
- package/dist/simulation/secrets.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { Race } from '@firestone-hs/reference-data';
|
|
2
2
|
import { BgsBattleOptions } from './bgs-battle-options';
|
|
3
3
|
import { BgsBoardInfo } from './bgs-board-info';
|
|
4
|
+
export interface BgsDebugStateEntity {
|
|
5
|
+
readonly entityId?: number;
|
|
6
|
+
readonly cardId?: string;
|
|
7
|
+
readonly attack?: number;
|
|
8
|
+
readonly health?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface BgsDebugState {
|
|
11
|
+
readonly forcedCurrentAttacker: number;
|
|
12
|
+
readonly forcedFaceOffBase: Array<{
|
|
13
|
+
readonly attacker: BgsDebugStateEntity;
|
|
14
|
+
readonly defender: BgsDebugStateEntity;
|
|
15
|
+
}>;
|
|
16
|
+
readonly forcedRandomPicks?: readonly {
|
|
17
|
+
source: BgsDebugStateEntity;
|
|
18
|
+
target: BgsDebugStateEntity;
|
|
19
|
+
}[];
|
|
20
|
+
readonly forcedTimewarpedWarghoulTargets?: readonly BgsDebugStateEntity[];
|
|
21
|
+
}
|
|
4
22
|
export interface BgsBattleInfo {
|
|
5
23
|
readonly playerBoard: BgsBoardInfo;
|
|
6
24
|
readonly playerTeammateBoard?: BgsBoardInfo;
|
|
@@ -9,6 +27,7 @@ export interface BgsBattleInfo {
|
|
|
9
27
|
readonly options: BgsBattleOptions;
|
|
10
28
|
readonly gameState: BgsGameState;
|
|
11
29
|
readonly heroHasDied?: boolean;
|
|
30
|
+
readonly debugState?: BgsDebugState;
|
|
12
31
|
}
|
|
13
32
|
export interface BgsGameState {
|
|
14
33
|
readonly currentTurn: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bgs-battle-info.js","sourceRoot":"","sources":["../src/bgs-battle-info.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\
|
|
1
|
+
{"version":3,"file":"bgs-battle-info.js","sourceRoot":"","sources":["../src/bgs-battle-info.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\nimport { BgsBattleOptions } from './bgs-battle-options';\nimport { BgsBoardInfo } from './bgs-board-info';\n\n/** Entity reference for debug state (entityId, or cardId+attack+health for spawned minions). */\nexport interface BgsDebugStateEntity {\n\treadonly entityId?: number;\n\treadonly cardId?: string;\n\treadonly attack?: number;\n\treadonly health?: number;\n}\n\n/** Debug state for bug reproduction: forces attack order and random effects from the real game. */\nexport interface BgsDebugState {\n\treadonly forcedCurrentAttacker: number;\n\treadonly forcedFaceOffBase: Array<{\n\t\treadonly attacker: BgsDebugStateEntity;\n\t\treadonly defender: BgsDebugStateEntity;\n\t}>;\n\t/** Forced random picks keyed by source entity (e.g. Warghoul) -> target (e.g. neighbour). */\n\treadonly forcedRandomPicks?: readonly { source: BgsDebugStateEntity; target: BgsDebugStateEntity }[];\n\t/** @deprecated Use forcedRandomPicks. Kept for backward compat with old bug reports. */\n\treadonly forcedTimewarpedWarghoulTargets?: readonly BgsDebugStateEntity[];\n}\n\nexport interface BgsBattleInfo {\n\treadonly playerBoard: BgsBoardInfo;\n\treadonly playerTeammateBoard?: BgsBoardInfo;\n\treadonly opponentBoard: BgsBoardInfo;\n\treadonly opponentTeammateBoard?: BgsBoardInfo;\n\treadonly options: BgsBattleOptions;\n\treadonly gameState: BgsGameState;\n\treadonly heroHasDied?: boolean;\n\t/** When present, simulator uses this to force attack sequence (e.g. from bug report). */\n\treadonly debugState?: BgsDebugState;\n}\n\nexport interface BgsGameState {\n\treadonly currentTurn: number;\n\treadonly validTribes?: readonly Race[];\n\treadonly anomalies?: readonly string[];\n}\n"]}
|
|
@@ -7,7 +7,7 @@ exports.Photobomber = {
|
|
|
7
7
|
cardIds: ["BG34_780", "BG34_780_G"],
|
|
8
8
|
deathrattleSpawn: (minion, input) => {
|
|
9
9
|
const loops = minion.cardId === "BG34_780_G" ? 2 : 1;
|
|
10
|
-
const damage = minion.scriptDataNum1 || 2 + input.boardWithDeadEntityHero.globalInfo.TavernSpellsCastThisGame;
|
|
10
|
+
const damage = minion.scriptDataNum1 || 2 * (1 + input.boardWithDeadEntityHero.globalInfo.TavernSpellsCastThisGame);
|
|
11
11
|
for (let i = 0; i < loops; i++) {
|
|
12
12
|
const target = (0, utils_1.pickRandomHighestHealth)(input.otherBoard);
|
|
13
13
|
if (!!target) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"photobomber.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/photobomber.ts"],"names":[],"mappings":";;;AAEA,mDAAkE;AAClE,uDAAgE;AAInD,QAAA,WAAW,GAAyB;IAChD,OAAO,EAAE,0BAA8D;IACvE,gBAAgB,EAAE,CAAC,MAAmB,EAAE,KAAgC,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,iBAAmC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"photobomber.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/photobomber.ts"],"names":[],"mappings":";;;AAEA,mDAAkE;AAClE,uDAAgE;AAInD,QAAA,WAAW,GAAyB;IAChD,OAAO,EAAE,0BAA8D;IACvE,gBAAgB,EAAE,CAAC,MAAmB,EAAE,KAAgC,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,iBAAmC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,MAAM,GACX,MAAM,CAAC,cAAc,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,uBAAuB,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC;QACtG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,IAAA,+BAAuB,EAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,CAAC,CAAC,MAAM,EAAE;gBACb,IAAA,2BAAkB,EACjB,MAAM,EACN,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,cAAc,EACpB,MAAM,EACN,MAAM,EACN,KAAK,CAAC,mBAAmB,EACzB,KAAK,CAAC,uBAAuB,EAC7B,KAAK,CAAC,SAAS,CACf,CAAC;aACF;SACD;QACD,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAAC","sourcesContent":["import { BoardEntity } from '../../../board-entity';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { pickRandomHighestHealth } from '../../../services/utils';\r\nimport { dealDamageToMinion } from '../../../simulation/attack';\r\nimport { DeathrattleTriggeredInput } from '../../../simulation/deathrattle-on-trigger';\r\nimport { DeathrattleSpawnCard } from '../../card.interface';\r\n\r\nexport const Photobomber: DeathrattleSpawnCard = {\r\n\tcardIds: [CardIds.Photobomber_BG34_780, CardIds.Photobomber_BG34_780_G],\r\n\tdeathrattleSpawn: (minion: BoardEntity, input: DeathrattleTriggeredInput) => {\r\n\t\tconst loops = minion.cardId === CardIds.Photobomber_BG34_780_G ? 2 : 1;\r\n\t\tconst damage =\r\n\t\t\tminion.scriptDataNum1 || 2 * (1 + input.boardWithDeadEntityHero.globalInfo.TavernSpellsCastThisGame);\r\n\t\tfor (let i = 0; i < loops; i++) {\r\n\t\t\tconst target = pickRandomHighestHealth(input.otherBoard);\r\n\t\t\tif (!!target) {\r\n\t\t\t\tdealDamageToMinion(\r\n\t\t\t\t\ttarget,\r\n\t\t\t\t\tinput.otherBoard,\r\n\t\t\t\t\tinput.otherBoardHero,\r\n\t\t\t\t\tminion,\r\n\t\t\t\t\tdamage,\r\n\t\t\t\t\tinput.boardWithDeadEntity,\r\n\t\t\t\t\tinput.boardWithDeadEntityHero,\r\n\t\t\t\t\tinput.gameState,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn [];\r\n\t},\r\n};\r\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { OnOtherSpawnedCard } from '../../card.interface';
|
|
2
|
-
export declare const TimewarpedEmbalmer: OnOtherSpawnedCard;
|
|
1
|
+
import { DefaultChargesCard, OnOtherSpawnedCard } from '../../card.interface';
|
|
2
|
+
export declare const TimewarpedEmbalmer: OnOtherSpawnedCard & DefaultChargesCard;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TimewarpedEmbalmer = void 0;
|
|
4
|
+
const reborn_1 = require("../../../keywords/reborn");
|
|
4
5
|
exports.TimewarpedEmbalmer = {
|
|
5
6
|
cardIds: ["BG34_Giant_332", "BG34_Giant_332_G"],
|
|
7
|
+
defaultCharges: (entity) => entity.scriptDataNum1 || 1,
|
|
6
8
|
onOtherSpawned: (minion, input) => {
|
|
9
|
+
if (minion.abiityChargesLeft > 0) {
|
|
10
|
+
minion.abiityChargesLeft--;
|
|
11
|
+
const target = input.spawned;
|
|
12
|
+
(0, reborn_1.updateReborn)(target, true, input.board, input.hero, input.otherHero, input.gameState);
|
|
13
|
+
}
|
|
7
14
|
},
|
|
8
15
|
};
|
|
9
16
|
//# sourceMappingURL=timewarped-embalmer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timewarped-embalmer.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/timewarped-embalmer.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"timewarped-embalmer.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/timewarped-embalmer.ts"],"names":[],"mappings":";;;AACA,qDAAwD;AAK3C,QAAA,kBAAkB,GAA4C;IAC1E,OAAO,EAAE,sCAAwF;IACjG,cAAc,EAAE,CAAC,MAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC;IACnE,cAAc,EAAE,CAAC,MAAmB,EAAE,KAAwB,EAAE,EAAE;QACjE,IAAI,MAAM,CAAC,iBAAiB,GAAG,CAAC,EAAE;YACjC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC;YAC7B,IAAA,qBAAY,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;SACtF;IACF,CAAC;CACD,CAAC","sourcesContent":["import { BoardEntity } from '../../../board-entity';\r\nimport { updateReborn } from '../../../keywords/reborn';\r\nimport { CardIds } from '../../../services/card-ids';\r\nimport { OnOtherSpawnInput } from '../../../simulation/add-minion-to-board';\r\nimport { DefaultChargesCard, OnOtherSpawnedCard } from '../../card.interface';\r\n\r\nexport const TimewarpedEmbalmer: OnOtherSpawnedCard & DefaultChargesCard = {\r\n\tcardIds: [CardIds.TimewarpedEmbalmer_BG34_Giant_332, CardIds.TimewarpedEmbalmer_BG34_Giant_332_G],\r\n\tdefaultCharges: (entity: BoardEntity) => entity.scriptDataNum1 || 1,\r\n\tonOtherSpawned: (minion: BoardEntity, input: OnOtherSpawnInput) => {\r\n\t\tif (minion.abiityChargesLeft > 0) {\r\n\t\t\tminion.abiityChargesLeft--;\r\n\t\t\tconst target = input.spawned;\r\n\t\t\tupdateReborn(target, true, input.board, input.hero, input.otherHero, input.gameState);\r\n\t\t}\r\n\t},\r\n};\r\n"]}
|
|
@@ -14,9 +14,14 @@ exports.TimewarpedWarghoul = {
|
|
|
14
14
|
(0, deathrattle_utils_1.hasValidDeathrattle)(e, input.boardWithDeadEntityHero, input.gameState) &&
|
|
15
15
|
!exports.TimewarpedWarghoul.cardIds.includes(e.cardId) &&
|
|
16
16
|
e.entityId !== minion.entityId);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
let neighbours;
|
|
18
|
+
if (minion.cardId === "BG34_Giant_331_G") {
|
|
19
|
+
neighbours = allNeighbours;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const chosen = (0, utils_1.pickRandom)(allNeighbours, minion);
|
|
23
|
+
neighbours = chosen ? [chosen] : [];
|
|
24
|
+
}
|
|
20
25
|
if (neighbours.length === 0) {
|
|
21
26
|
callStackDepth--;
|
|
22
27
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timewarped-warghoul.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/timewarped-warghoul.ts"],"names":[],"mappings":";;;AAEA,mDAAqD;AACrD,uDAA2D;AAE3D,6FAA4F;AAC5F,6EAA4E;AAG5E,IAAI,cAAc,GAAG,CAAC,CAAC;AAEV,QAAA,kBAAkB,GAAyB;IACvD,OAAO,EAAE,sCAAwF;IACjG,gBAAgB,EAAE,CAAC,MAAmB,EAAE,KAAgC,EAAE,EAAE;QAC3E,cAAc,EAAE,CAAC;QACjB,MAAM,aAAa,GAAG,IAAA,sBAAa,EAAC,KAAK,CAAC,mBAAmB,EAAE,MAAM,EAAE,KAAK,CAAC,wBAAwB,CAAC,CAAC,MAAM,CAC5G,CAAC,CAAC,EAAE,EAAE,CACL,CAAC,CAAC,CAAC;YACH,IAAA,uCAAmB,EAAC,CAAC,EAAE,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,SAAS,CAAC;YACtE,CAAC,0BAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;YAI9C,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAG/B,CAAC;QACF,
|
|
1
|
+
{"version":3,"file":"timewarped-warghoul.js","sourceRoot":"","sources":["../../../../src/cards/impl/minion/timewarped-warghoul.ts"],"names":[],"mappings":";;;AAEA,mDAAqD;AACrD,uDAA2D;AAE3D,6FAA4F;AAC5F,6EAA4E;AAG5E,IAAI,cAAc,GAAG,CAAC,CAAC;AAEV,QAAA,kBAAkB,GAAyB;IACvD,OAAO,EAAE,sCAAwF;IACjG,gBAAgB,EAAE,CAAC,MAAmB,EAAE,KAAgC,EAAE,EAAE;QAC3E,cAAc,EAAE,CAAC;QACjB,MAAM,aAAa,GAAG,IAAA,sBAAa,EAAC,KAAK,CAAC,mBAAmB,EAAE,MAAM,EAAE,KAAK,CAAC,wBAAwB,CAAC,CAAC,MAAM,CAC5G,CAAC,CAAC,EAAE,EAAE,CACL,CAAC,CAAC,CAAC;YACH,IAAA,uCAAmB,EAAC,CAAC,EAAE,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,SAAS,CAAC;YACtE,CAAC,0BAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;YAI9C,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAG/B,CAAC;QACF,IAAI,UAAyB,CAAC;QAC9B,IAAI,MAAM,CAAC,MAAM,uBAAgD,EAAE;YAClE,UAAU,GAAG,aAAa,CAAC;SAC3B;aAAM;YAEN,MAAM,MAAM,GAAG,IAAA,kBAAU,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACjD,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACpC;QACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;YAC5B,cAAc,EAAE,CAAC;YACjB,OAAO,EAAE,CAAC;SACV;QACD,IAAI,cAAc,GAAG,EAAE,EAAE;YACxB,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;SACzE;QACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;YACnC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAC5C,MAAM,EACN,SAAS,EACT,KAAK,CAAC,mBAAmB,EACzB,KAAK,CAAC,uBAAuB,EAC7B,KAAK,CAAC,cAAc,CACpB,CAAC;YACF,MAAM,cAAc,GACnB,KAAK,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YACvF,IAAA,uDAA2B,EAC1B,SAAS,EACT,cAAc,EACd,CAAC,SAAS,CAAC,EACX,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAC1F,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAC1F,KAAK,CAAC,SAAS,EACf,KAAK,CACL,CAAC;SACF;QACD,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAAC","sourcesContent":["import { BoardEntity } from '../../../board-entity';\nimport { CardIds } from '../../../services/card-ids';\nimport { pickRandom } from '../../../services/utils';\nimport { getNeighbours } from '../../../simulation/attack';\nimport { DeathrattleTriggeredInput } from '../../../simulation/deathrattle-on-trigger';\nimport { processDeathrattleForMinion } from '../../../simulation/deathrattle-orchestration';\nimport { hasValidDeathrattle } from '../../../simulation/deathrattle-utils';\nimport { DeathrattleSpawnCard } from '../../card.interface';\n\nlet callStackDepth = 0; // Global variable to track call stack depth\n\nexport const TimewarpedWarghoul: DeathrattleSpawnCard = {\n\tcardIds: [CardIds.TimewarpedWarghoul_BG34_Giant_331, CardIds.TimewarpedWarghoul_BG34_Giant_331_G],\n\tdeathrattleSpawn: (minion: BoardEntity, input: DeathrattleTriggeredInput) => {\n\t\tcallStackDepth++;\n\t\tconst allNeighbours = getNeighbours(input.boardWithDeadEntity, minion, input.deadEntityIndexFromRight).filter(\n\t\t\t(e) =>\n\t\t\t\t!!e &&\n\t\t\t\thasValidDeathrattle(e, input.boardWithDeadEntityHero, input.gameState) &&\n\t\t\t\t!TimewarpedWarghoul.cardIds.includes(e.cardId) &&\n\t\t\t\t// The Warghoul will proc all the Whirl-O-Trons deathrattles but the copied deathrattle\n\t\t\t\t// cannot re-proc on the Warghoul itself. (If you manage to get a set up with 2 Whirl-O-Trons,\n\t\t\t\t// Macaw and Warghoul then congrats! Things may start to loop)\n\t\t\t\te.entityId !== minion.entityId,\n\t\t\t// !e.enchantments?.some((e) => TimewarpedWarghoul.cardIds.includes(e.cardId)) &&\n\t\t\t// !e.rememberedDeathrattles?.some((e) => TimewarpedWarghoul.cardIds.includes(e.cardId)),\n\t\t);\n\t\tlet neighbours: BoardEntity[];\n\t\tif (minion.cardId === CardIds.TimewarpedWarghoul_BG34_Giant_331_G) {\n\t\t\tneighbours = allNeighbours;\n\t\t} else {\n\t\t\t// Non-golden: pick one random neighbour\n\t\t\tconst chosen = pickRandom(allNeighbours, minion);\n\t\t\tneighbours = chosen ? [chosen] : [];\n\t\t}\n\t\tif (neighbours.length === 0) {\n\t\t\tcallStackDepth--;\n\t\t\treturn [];\n\t\t}\n\t\tif (callStackDepth > 10) {\n\t\t\tconsole.log('warning: timewarped warghoul call stack depth is too deep');\n\t\t}\n\t\tfor (const neighbour of neighbours) {\n\t\t\tinput.gameState.spectator.registerPowerTarget(\n\t\t\t\tminion,\n\t\t\t\tneighbour,\n\t\t\t\tinput.boardWithDeadEntity,\n\t\t\t\tinput.boardWithDeadEntityHero,\n\t\t\t\tinput.otherBoardHero,\n\t\t\t);\n\t\t\tconst indexFromRight =\n\t\t\t\tinput.boardWithDeadEntity.length - (input.boardWithDeadEntity.indexOf(neighbour) + 1);\n\t\t\tprocessDeathrattleForMinion(\n\t\t\t\tneighbour,\n\t\t\t\tindexFromRight,\n\t\t\t\t[neighbour],\n\t\t\t\tneighbour.friendly ? input.gameState.gameState.player : input.gameState.gameState.opponent,\n\t\t\t\tneighbour.friendly ? input.gameState.gameState.opponent : input.gameState.gameState.player,\n\t\t\t\tinput.gameState,\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\t\tcallStackDepth--;\n\t\treturn [];\n\t},\n};\n"]}
|
package/dist/debug-state.d.ts
CHANGED
|
@@ -10,7 +10,15 @@ export declare const debugState: {
|
|
|
10
10
|
attacker: ForcedFaceOffEntity;
|
|
11
11
|
defender: ForcedFaceOffEntity;
|
|
12
12
|
}[];
|
|
13
|
+
forcedRandomPicks: {
|
|
14
|
+
source: ForcedFaceOffEntity;
|
|
15
|
+
target: ForcedFaceOffEntity;
|
|
16
|
+
}[];
|
|
13
17
|
isCorrectEntity: (proposedEntity: ForcedFaceOffEntity, actualEntity: BoardEntity) => boolean;
|
|
18
|
+
forcedRandomPicksBase: {
|
|
19
|
+
source: ForcedFaceOffEntity;
|
|
20
|
+
target: ForcedFaceOffEntity;
|
|
21
|
+
}[];
|
|
14
22
|
onBattleStart: () => void;
|
|
15
23
|
};
|
|
16
24
|
export interface ForcedFaceOffEntity {
|
package/dist/debug-state.js
CHANGED
|
@@ -6,17 +6,25 @@ exports.debugState = {
|
|
|
6
6
|
forcedCurrentAttacker: null,
|
|
7
7
|
forcedFaceOff: [],
|
|
8
8
|
forcedFaceOffBase: [],
|
|
9
|
+
forcedRandomPicks: [],
|
|
9
10
|
isCorrectEntity: (proposedEntity, actualEntity) => {
|
|
10
11
|
if (proposedEntity.entityId) {
|
|
11
12
|
return proposedEntity.entityId === actualEntity.entityId;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
if (proposedEntity.cardId) {
|
|
15
|
+
const cardMatches = proposedEntity.cardId === actualEntity.cardId;
|
|
16
|
+
if (proposedEntity.attack != null && proposedEntity.health != null) {
|
|
17
|
+
return cardMatches && proposedEntity.attack === actualEntity.attack && proposedEntity.health === actualEntity.health;
|
|
18
|
+
}
|
|
19
|
+
return cardMatches;
|
|
15
20
|
}
|
|
16
|
-
return proposedEntity.attack === actualEntity.attack &&
|
|
21
|
+
return (proposedEntity.attack === actualEntity.attack &&
|
|
22
|
+
proposedEntity.health === actualEntity.health);
|
|
17
23
|
},
|
|
24
|
+
forcedRandomPicksBase: [],
|
|
18
25
|
onBattleStart: () => {
|
|
19
26
|
exports.debugState.forcedFaceOff = [...exports.debugState.forcedFaceOffBase];
|
|
27
|
+
exports.debugState.forcedRandomPicks = [...exports.debugState.forcedRandomPicksBase];
|
|
20
28
|
},
|
|
21
29
|
};
|
|
22
30
|
//# sourceMappingURL=debug-state.js.map
|
package/dist/debug-state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-state.js","sourceRoot":"","sources":["../src/debug-state.ts"],"names":[],"mappings":";;;AAEa,QAAA,UAAU,GAAG;IACzB,MAAM,EAAE,KAAK;IACb,qBAAqB,EAAE,IAAqB;IAC5C,aAAa,EAAE,EAAwE;IACvF,iBAAiB,EAAE,EAAwE;
|
|
1
|
+
{"version":3,"file":"debug-state.js","sourceRoot":"","sources":["../src/debug-state.ts"],"names":[],"mappings":";;;AAEa,QAAA,UAAU,GAAG;IACzB,MAAM,EAAE,KAAK;IACb,qBAAqB,EAAE,IAAqB;IAC5C,aAAa,EAAE,EAAwE;IACvF,iBAAiB,EAAE,EAAwE;IAE3F,iBAAiB,EAAE,EAAoE;IACvF,eAAe,EAAE,CAAC,cAAmC,EAAE,YAAyB,EAAW,EAAE;QAC5F,IAAI,cAAc,CAAC,QAAQ,EAAE;YAC5B,OAAO,cAAc,CAAC,QAAQ,KAAK,YAAY,CAAC,QAAQ,CAAC;SACzD;QACD,IAAI,cAAc,CAAC,MAAM,EAAE;YAC1B,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,CAAC;YAClE,IAAI,cAAc,CAAC,MAAM,IAAI,IAAI,IAAI,cAAc,CAAC,MAAM,IAAI,IAAI,EAAE;gBACnE,OAAO,WAAW,IAAI,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,CAAC;aACrH;YACD,OAAO,WAAW,CAAC;SACnB;QACD,OAAO,CACN,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM;YAC7C,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,CAC7C,CAAC;IACH,CAAC;IACD,qBAAqB,EAAE,EAAoE;IAC3F,aAAa,EAAE,GAAG,EAAE;QACnB,kBAAU,CAAC,aAAa,GAAG,CAAC,GAAG,kBAAU,CAAC,iBAAiB,CAAC,CAAC;QAC7D,kBAAU,CAAC,iBAAiB,GAAG,CAAC,GAAG,kBAAU,CAAC,qBAAqB,CAAC,CAAC;IACtE,CAAC;CACD,CAAC","sourcesContent":["import { BoardEntity } from './board-entity';\n\nexport const debugState = {\n\tactive: false,\n\tforcedCurrentAttacker: null as number | null,\n\tforcedFaceOff: [] as { attacker: ForcedFaceOffEntity; defender: ForcedFaceOffEntity }[],\n\tforcedFaceOffBase: [] as { attacker: ForcedFaceOffEntity; defender: ForcedFaceOffEntity }[],\n\t/** Forced random picks: source -> target. Matched by source entity (like face-offs match by attacker). */\n\tforcedRandomPicks: [] as { source: ForcedFaceOffEntity; target: ForcedFaceOffEntity }[],\n\tisCorrectEntity: (proposedEntity: ForcedFaceOffEntity, actualEntity: BoardEntity): boolean => {\n\t\tif (proposedEntity.entityId) {\n\t\t\treturn proposedEntity.entityId === actualEntity.entityId;\n\t\t}\n\t\tif (proposedEntity.cardId) {\n\t\t\tconst cardMatches = proposedEntity.cardId === actualEntity.cardId;\n\t\t\tif (proposedEntity.attack != null && proposedEntity.health != null) {\n\t\t\t\treturn cardMatches && proposedEntity.attack === actualEntity.attack && proposedEntity.health === actualEntity.health;\n\t\t\t}\n\t\t\treturn cardMatches;\n\t\t}\n\t\treturn (\n\t\t\tproposedEntity.attack === actualEntity.attack &&\n\t\t\tproposedEntity.health === actualEntity.health\n\t\t);\n\t},\n\tforcedRandomPicksBase: [] as { source: ForcedFaceOffEntity; target: ForcedFaceOffEntity }[],\n\tonBattleStart: () => {\n\t\tdebugState.forcedFaceOff = [...debugState.forcedFaceOffBase];\n\t\tdebugState.forcedRandomPicks = [...debugState.forcedRandomPicksBase];\n\t},\n};\n\nexport interface ForcedFaceOffEntity {\n\tentityId?: number;\n\tcardId?: string;\n\tattack?: number;\n\thealth?: number;\n}\n"]}
|
package/dist/services/utils.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export declare const groupByFunction: <T>(keyExtractor: (obj: T) => string | num
|
|
|
5
5
|
[key: string]: readonly T[];
|
|
6
6
|
};
|
|
7
7
|
export { partitionArray, sleep };
|
|
8
|
-
export declare
|
|
8
|
+
export declare function pickRandom<T>(array: readonly T[]): T;
|
|
9
|
+
export declare function pickRandom<T extends BoardEntity>(array: readonly T[], sourceEntity: BoardEntity): T;
|
|
9
10
|
export declare const pickMultipleRandom: <T>(array: readonly T[], quantity: number) => T[];
|
|
10
11
|
export declare const pickRandomAlive: (board: BoardEntity[]) => BoardEntity;
|
|
11
12
|
export declare const pickMultipleRandomAlive: (board: BoardEntity[], quantity: number) => BoardEntity[];
|
package/dist/services/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findLast = exports.shuffleArray = exports.pickMultipleRandomDifferent = exports.decode = exports.encode = exports.pickRandomHighestHealth = exports.pickRandomHighestAttack = exports.pickRandomLowestAttack = exports.pickRandomLowestHealth = exports.pickMultipleRandomAlive = exports.pickRandomAlive = exports.pickMultipleRandom = exports.pickRandom = exports.sleep = exports.partitionArray = exports.groupByFunction = void 0;
|
|
4
|
+
const debug_state_1 = require("../debug-state");
|
|
4
5
|
function partitionArray(array, partitionSize) {
|
|
5
6
|
const workingCopy = [...array];
|
|
6
7
|
const result = [];
|
|
@@ -24,18 +25,33 @@ const groupByFunction = (keyExtractor) => (array) => {
|
|
|
24
25
|
}, {});
|
|
25
26
|
};
|
|
26
27
|
exports.groupByFunction = groupByFunction;
|
|
27
|
-
|
|
28
|
+
function pickRandom(array, sourceEntity) {
|
|
28
29
|
if (!(array === null || array === void 0 ? void 0 : array.length)) {
|
|
29
30
|
return null;
|
|
30
31
|
}
|
|
32
|
+
if (sourceEntity &&
|
|
33
|
+
debug_state_1.debugState.active &&
|
|
34
|
+
array.length > 0 &&
|
|
35
|
+
typeof array[0] === 'object' &&
|
|
36
|
+
array[0] != null &&
|
|
37
|
+
'entityId' in array[0]) {
|
|
38
|
+
const forced = debug_state_1.debugState.forcedRandomPicks.find((p) => debug_state_1.debugState.isCorrectEntity(p.source, sourceEntity));
|
|
39
|
+
if (forced) {
|
|
40
|
+
const match = array.find((c) => debug_state_1.debugState.isCorrectEntity(forced.target, c));
|
|
41
|
+
debug_state_1.debugState.forcedRandomPicks = debug_state_1.debugState.forcedRandomPicks.filter((p) => p !== forced);
|
|
42
|
+
if (match) {
|
|
43
|
+
return match;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
31
47
|
return array[Math.floor(Math.random() * array.length)];
|
|
32
|
-
}
|
|
48
|
+
}
|
|
33
49
|
exports.pickRandom = pickRandom;
|
|
34
50
|
const pickMultipleRandom = (array, quantity) => {
|
|
35
51
|
const picked = [];
|
|
36
52
|
for (let i = 0; i < quantity; i++) {
|
|
37
53
|
const target = array.filter((e) => !picked.includes(e));
|
|
38
|
-
const chosenEntity =
|
|
54
|
+
const chosenEntity = pickRandom(target);
|
|
39
55
|
if (!!chosenEntity) {
|
|
40
56
|
picked.push(chosenEntity);
|
|
41
57
|
}
|
|
@@ -45,7 +61,7 @@ const pickMultipleRandom = (array, quantity) => {
|
|
|
45
61
|
exports.pickMultipleRandom = pickMultipleRandom;
|
|
46
62
|
const pickRandomAlive = (board) => {
|
|
47
63
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);
|
|
48
|
-
const chosenEntity =
|
|
64
|
+
const chosenEntity = pickRandom(targetBoard);
|
|
49
65
|
return chosenEntity;
|
|
50
66
|
};
|
|
51
67
|
exports.pickRandomAlive = pickRandomAlive;
|
|
@@ -53,7 +69,7 @@ const pickMultipleRandomAlive = (board, quantity) => {
|
|
|
53
69
|
const picked = [];
|
|
54
70
|
for (let i = 0; i < quantity; i++) {
|
|
55
71
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead).filter((e) => !picked.includes(e));
|
|
56
|
-
const chosenEntity =
|
|
72
|
+
const chosenEntity = pickRandom(targetBoard);
|
|
57
73
|
if (!!chosenEntity) {
|
|
58
74
|
picked.push(chosenEntity);
|
|
59
75
|
}
|
|
@@ -65,7 +81,7 @@ const pickRandomLowestHealth = (board) => {
|
|
|
65
81
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);
|
|
66
82
|
const lowestHealth = Math.min(...targetBoard.map((e) => e.health));
|
|
67
83
|
const entitiesWithLowestHealth = targetBoard.filter((e) => e.health === lowestHealth);
|
|
68
|
-
const chosenEntity =
|
|
84
|
+
const chosenEntity = pickRandom(entitiesWithLowestHealth);
|
|
69
85
|
return chosenEntity;
|
|
70
86
|
};
|
|
71
87
|
exports.pickRandomLowestHealth = pickRandomLowestHealth;
|
|
@@ -73,7 +89,7 @@ const pickRandomLowestAttack = (board) => {
|
|
|
73
89
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);
|
|
74
90
|
const lowestAttack = Math.min(...targetBoard.map((e) => e.attack));
|
|
75
91
|
const entitiesWithLowestAttack = targetBoard.filter((e) => e.attack === lowestAttack);
|
|
76
|
-
const chosenEntity =
|
|
92
|
+
const chosenEntity = pickRandom(entitiesWithLowestAttack);
|
|
77
93
|
return chosenEntity;
|
|
78
94
|
};
|
|
79
95
|
exports.pickRandomLowestAttack = pickRandomLowestAttack;
|
|
@@ -81,7 +97,7 @@ const pickRandomHighestAttack = (board) => {
|
|
|
81
97
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);
|
|
82
98
|
const highestAttack = Math.max(...targetBoard.map((e) => e.attack));
|
|
83
99
|
const entitiesWithHighestAttack = targetBoard.filter((e) => e.attack === highestAttack);
|
|
84
|
-
const chosenEntity =
|
|
100
|
+
const chosenEntity = pickRandom(entitiesWithHighestAttack);
|
|
85
101
|
return chosenEntity;
|
|
86
102
|
};
|
|
87
103
|
exports.pickRandomHighestAttack = pickRandomHighestAttack;
|
|
@@ -89,7 +105,7 @@ const pickRandomHighestHealth = (board) => {
|
|
|
89
105
|
const targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);
|
|
90
106
|
const highestHealth = Math.max(...targetBoard.map((e) => e.health));
|
|
91
107
|
const entitiesWithHighestHealth = targetBoard.filter((e) => e.health === highestHealth);
|
|
92
|
-
const chosenEntity =
|
|
108
|
+
const chosenEntity = pickRandom(entitiesWithHighestHealth);
|
|
93
109
|
return chosenEntity;
|
|
94
110
|
};
|
|
95
111
|
exports.pickRandomHighestHealth = pickRandomHighestHealth;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/services/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { BoardEntity } from '../board-entity';\r\n\r\nfunction partitionArray<T>(array: readonly T[], partitionSize: number): readonly T[][] {\r\n\tconst workingCopy: T[] = [...array];\r\n\tconst result: T[][] = [];\r\n\twhile (workingCopy.length) {\r\n\t\tresult.push(workingCopy.splice(0, partitionSize));\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nasync function sleep(ms) {\r\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport const groupByFunction =\r\n\t<T>(keyExtractor: (obj: T) => string | number) =>\r\n\t(array: readonly T[]): { [key: string]: readonly T[] } => {\r\n\t\treturn (array ?? []).reduce((objectsByKeyValue, obj) => {\r\n\t\t\tconst value = keyExtractor(obj);\r\n\t\t\tobjectsByKeyValue[value] = objectsByKeyValue[value] ?? [];\r\n\t\t\t// Using push instead of concat is thousands of times faster on big arrays\r\n\t\t\tobjectsByKeyValue[value].push(obj);\r\n\t\t\treturn objectsByKeyValue;\r\n\t\t}, {});\r\n\t};\r\n\r\nexport { partitionArray, sleep };\r\n\r\nexport const pickRandom = <T>(array: readonly T[]): T => {\r\n\tif (!array?.length) {\r\n\t\treturn null;\r\n\t}\r\n\treturn array[Math.floor(Math.random() * array.length)];\r\n};\r\n\r\nexport const pickMultipleRandom = <T>(array: readonly T[], quantity: number): T[] => {\r\n\tconst picked: T[] = [];\r\n\tfor (let i = 0; i < quantity; i++) {\r\n\t\tconst target = array.filter((e) => !picked.includes(e));\r\n\t\tconst chosenEntity = pickRandom(target);\r\n\t\tif (!!chosenEntity) {\r\n\t\t\tpicked.push(chosenEntity);\r\n\t\t}\r\n\t}\r\n\treturn picked;\r\n};\r\n\r\nexport const pickRandomAlive = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst chosenEntity = pickRandom(targetBoard);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickMultipleRandomAlive = (board: BoardEntity[], quantity: number): BoardEntity[] => {\r\n\tconst picked: BoardEntity[] = [];\r\n\tfor (let i = 0; i < quantity; i++) {\r\n\t\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead).filter((e) => !picked.includes(e));\r\n\t\tconst chosenEntity = pickRandom(targetBoard);\r\n\t\tif (!!chosenEntity) {\r\n\t\t\tpicked.push(chosenEntity);\r\n\t\t}\r\n\t}\r\n\treturn picked;\r\n};\r\n\r\nexport const pickRandomLowestHealth = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst lowestHealth = Math.min(...targetBoard.map((e) => e.health));\r\n\tconst entitiesWithLowestHealth = targetBoard.filter((e) => e.health === lowestHealth);\r\n\tconst chosenEntity = pickRandom(entitiesWithLowestHealth);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomLowestAttack = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst lowestAttack = Math.min(...targetBoard.map((e) => e.attack));\r\n\tconst entitiesWithLowestAttack = targetBoard.filter((e) => e.attack === lowestAttack);\r\n\tconst chosenEntity = pickRandom(entitiesWithLowestAttack);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomHighestAttack = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst highestAttack = Math.max(...targetBoard.map((e) => e.attack));\r\n\tconst entitiesWithHighestAttack = targetBoard.filter((e) => e.attack === highestAttack);\r\n\tconst chosenEntity = pickRandom(entitiesWithHighestAttack);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomHighestHealth = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst highestHealth = Math.max(...targetBoard.map((e) => e.health));\r\n\tconst entitiesWithHighestHealth = targetBoard.filter((e) => e.health === highestHealth);\r\n\tconst chosenEntity = pickRandom(entitiesWithHighestHealth);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const encode = (input: string): string => {\r\n\t// return compressToEncodedURIComponent(input);\r\n\tconst buff = Buffer.from(input, 'utf-8');\r\n\tconst base64 = buff.toString('base64');\r\n\treturn base64;\r\n};\r\n\r\nexport const decode = (base64: string): string => {\r\n\tconst buff = Buffer.from(base64, 'base64');\r\n\tconst str = buff.toString('utf-8');\r\n\treturn str;\r\n};\r\n\r\nexport const pickMultipleRandomDifferent = <T>(list: T[], n: number): T[] => {\r\n\tconst shuffled = shuffleArray([...list]);\r\n\treturn shuffled.slice(0, n);\r\n};\r\n\r\n// https://stackoverflow.com/a/2450976/548701\r\nexport const shuffleArray = <T>(array: T[]): T[] => {\r\n\tlet currentIndex = array.length;\r\n\tlet randomIndex = 0;\r\n\r\n\t// While there remain elements to shuffle...\r\n\twhile (currentIndex != 0) {\r\n\t\t// Pick a remaining element...\r\n\t\trandomIndex = Math.floor(Math.random() * currentIndex);\r\n\t\tcurrentIndex--;\r\n\r\n\t\t// And swap it with the current element.\r\n\t\t[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];\r\n\t}\r\n\r\n\treturn array;\r\n};\r\n\r\nexport const findLast = <T>(\r\n\tarray: readonly T[],\r\n\tpredicate: (value: T, index: number, obj: readonly T[]) => unknown,\r\n): T => {\r\n\tconst filtred = array.filter(predicate);\r\n\tif (!filtred?.length) {\r\n\t\treturn null;\r\n\t}\r\n\tconst last = filtred[filtred.length - 1];\r\n\treturn last;\r\n};\r\n\r\nexport type Mutable<T> = {\r\n\t-readonly [P in keyof T]: T[P];\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/services/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { BoardEntity } from '../board-entity';\r\nimport { debugState } from '../debug-state';\r\n\r\nfunction partitionArray<T>(array: readonly T[], partitionSize: number): readonly T[][] {\r\n\tconst workingCopy: T[] = [...array];\r\n\tconst result: T[][] = [];\r\n\twhile (workingCopy.length) {\r\n\t\tresult.push(workingCopy.splice(0, partitionSize));\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nasync function sleep(ms) {\r\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nexport const groupByFunction =\r\n\t<T>(keyExtractor: (obj: T) => string | number) =>\r\n\t(array: readonly T[]): { [key: string]: readonly T[] } => {\r\n\t\treturn (array ?? []).reduce((objectsByKeyValue, obj) => {\r\n\t\t\tconst value = keyExtractor(obj);\r\n\t\t\tobjectsByKeyValue[value] = objectsByKeyValue[value] ?? [];\r\n\t\t\t// Using push instead of concat is thousands of times faster on big arrays\r\n\t\t\tobjectsByKeyValue[value].push(obj);\r\n\t\t\treturn objectsByKeyValue;\r\n\t\t}, {});\r\n\t};\r\n\r\nexport { partitionArray, sleep };\r\n\r\nexport function pickRandom<T>(array: readonly T[]): T;\r\nexport function pickRandom<T extends BoardEntity>(array: readonly T[], sourceEntity: BoardEntity): T;\r\nexport function pickRandom<T>(array: readonly T[], sourceEntity?: BoardEntity): T {\r\n\tif (!array?.length) {\r\n\t\treturn null;\r\n\t}\r\n\tif (\r\n\t\tsourceEntity &&\r\n\t\tdebugState.active &&\r\n\t\tarray.length > 0 &&\r\n\t\ttypeof array[0] === 'object' &&\r\n\t\tarray[0] != null &&\r\n\t\t'entityId' in array[0]\r\n\t) {\r\n\t\tconst forced = debugState.forcedRandomPicks.find((p) => debugState.isCorrectEntity(p.source, sourceEntity));\r\n\t\tif (forced) {\r\n\t\t\tconst match = (array as unknown as BoardEntity[]).find((c) => debugState.isCorrectEntity(forced.target, c));\r\n\t\t\t// Always consume when we have a matching source - each trigger gets its own pick (e.g. Titus doubles Warghoul)\r\n\t\t\tdebugState.forcedRandomPicks = debugState.forcedRandomPicks.filter((p) => p !== forced);\r\n\t\t\tif (match) {\r\n\t\t\t\treturn match as T;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn array[Math.floor(Math.random() * array.length)];\r\n}\r\n\r\nexport const pickMultipleRandom = <T>(array: readonly T[], quantity: number): T[] => {\r\n\tconst picked: T[] = [];\r\n\tfor (let i = 0; i < quantity; i++) {\r\n\t\tconst target = array.filter((e) => !picked.includes(e));\r\n\t\tconst chosenEntity = pickRandom(target);\r\n\t\tif (!!chosenEntity) {\r\n\t\t\tpicked.push(chosenEntity);\r\n\t\t}\r\n\t}\r\n\treturn picked;\r\n};\r\n\r\nexport const pickRandomAlive = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst chosenEntity = pickRandom(targetBoard);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickMultipleRandomAlive = (board: BoardEntity[], quantity: number): BoardEntity[] => {\r\n\tconst picked: BoardEntity[] = [];\r\n\tfor (let i = 0; i < quantity; i++) {\r\n\t\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead).filter((e) => !picked.includes(e));\r\n\t\tconst chosenEntity = pickRandom(targetBoard);\r\n\t\tif (!!chosenEntity) {\r\n\t\t\tpicked.push(chosenEntity);\r\n\t\t}\r\n\t}\r\n\treturn picked;\r\n};\r\n\r\nexport const pickRandomLowestHealth = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst lowestHealth = Math.min(...targetBoard.map((e) => e.health));\r\n\tconst entitiesWithLowestHealth = targetBoard.filter((e) => e.health === lowestHealth);\r\n\tconst chosenEntity = pickRandom(entitiesWithLowestHealth);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomLowestAttack = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst lowestAttack = Math.min(...targetBoard.map((e) => e.attack));\r\n\tconst entitiesWithLowestAttack = targetBoard.filter((e) => e.attack === lowestAttack);\r\n\tconst chosenEntity = pickRandom(entitiesWithLowestAttack);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomHighestAttack = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst highestAttack = Math.max(...targetBoard.map((e) => e.attack));\r\n\tconst entitiesWithHighestAttack = targetBoard.filter((e) => e.attack === highestAttack);\r\n\tconst chosenEntity = pickRandom(entitiesWithHighestAttack);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const pickRandomHighestHealth = (board: BoardEntity[]): BoardEntity => {\r\n\tconst targetBoard = board.filter((e) => e.health > 0 && !e.definitelyDead);\r\n\tconst highestHealth = Math.max(...targetBoard.map((e) => e.health));\r\n\tconst entitiesWithHighestHealth = targetBoard.filter((e) => e.health === highestHealth);\r\n\tconst chosenEntity = pickRandom(entitiesWithHighestHealth);\r\n\treturn chosenEntity;\r\n};\r\n\r\nexport const encode = (input: string): string => {\r\n\t// return compressToEncodedURIComponent(input);\r\n\tconst buff = Buffer.from(input, 'utf-8');\r\n\tconst base64 = buff.toString('base64');\r\n\treturn base64;\r\n};\r\n\r\nexport const decode = (base64: string): string => {\r\n\tconst buff = Buffer.from(base64, 'base64');\r\n\tconst str = buff.toString('utf-8');\r\n\treturn str;\r\n};\r\n\r\nexport const pickMultipleRandomDifferent = <T>(list: T[], n: number): T[] => {\r\n\tconst shuffled = shuffleArray([...list]);\r\n\treturn shuffled.slice(0, n);\r\n};\r\n\r\n// https://stackoverflow.com/a/2450976/548701\r\nexport const shuffleArray = <T>(array: T[]): T[] => {\r\n\tlet currentIndex = array.length;\r\n\tlet randomIndex = 0;\r\n\r\n\t// While there remain elements to shuffle...\r\n\twhile (currentIndex != 0) {\r\n\t\t// Pick a remaining element...\r\n\t\trandomIndex = Math.floor(Math.random() * currentIndex);\r\n\t\tcurrentIndex--;\r\n\r\n\t\t// And swap it with the current element.\r\n\t\t[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];\r\n\t}\r\n\r\n\treturn array;\r\n};\r\n\r\nexport const findLast = <T>(\r\n\tarray: readonly T[],\r\n\tpredicate: (value: T, index: number, obj: readonly T[]) => unknown,\r\n): T => {\r\n\tconst filtred = array.filter(predicate);\r\n\tif (!filtred?.length) {\r\n\t\treturn null;\r\n\t}\r\n\tconst last = filtred[filtred.length - 1];\r\n\treturn last;\r\n};\r\n\r\nexport type Mutable<T> = {\r\n\t-readonly [P in keyof T]: T[P];\r\n};\r\n"]}
|
|
@@ -5,6 +5,7 @@ const reference_data_1 = require("@firestone-hs/reference-data");
|
|
|
5
5
|
const card_interface_1 = require("./cards/card.interface");
|
|
6
6
|
const cards_data_1 = require("./cards/cards-data");
|
|
7
7
|
const _card_mappings_1 = require("./cards/impl/_card-mappings");
|
|
8
|
+
const debug_state_1 = require("./debug-state");
|
|
8
9
|
const input_clone_1 = require("./input-clone");
|
|
9
10
|
const input_sanitation_1 = require("./input-sanitation");
|
|
10
11
|
const shared_state_1 = require("./simulation/shared-state");
|
|
@@ -40,7 +41,7 @@ exports.default = async (event) => {
|
|
|
40
41
|
return response;
|
|
41
42
|
};
|
|
42
43
|
const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
43
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
44
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
44
45
|
if (!((_a = cards === null || cards === void 0 ? void 0 : cards.getCards()) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
45
46
|
console.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);
|
|
46
47
|
return null;
|
|
@@ -74,85 +75,108 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
74
75
|
};
|
|
75
76
|
const spectator = new spectator_1.Spectator(includeOutcomeSamples);
|
|
76
77
|
const inputReady = (0, input_sanitation_1.buildFinalInput)(battleInput, cards, cardsData);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
78
|
+
if (battleInput.debugState) {
|
|
79
|
+
debug_state_1.debugState.active = true;
|
|
80
|
+
debug_state_1.debugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;
|
|
81
|
+
debug_state_1.debugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({
|
|
82
|
+
attacker: { ...f.attacker },
|
|
83
|
+
defender: { ...f.defender },
|
|
84
|
+
}));
|
|
85
|
+
const rawPicks = (_p = (_m = battleInput.debugState.forcedRandomPicks) !== null && _m !== void 0 ? _m : (_o = battleInput.debugState.forcedTimewarpedWarghoulTargets) === null || _o === void 0 ? void 0 : _o.map((target) => ({
|
|
86
|
+
source: { cardId: 'BG34_Giant_331' },
|
|
87
|
+
target,
|
|
88
|
+
}))) !== null && _p !== void 0 ? _p : [];
|
|
89
|
+
debug_state_1.debugState.forcedRandomPicksBase = rawPicks.map((p) => ({
|
|
90
|
+
source: { ...p.source },
|
|
91
|
+
target: { ...p.target },
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
!((_q = battleInput.options) === null || _q === void 0 ? void 0 : _q.skipInfoLogs) && console.time('simulation');
|
|
96
|
+
const outcomes = {};
|
|
97
|
+
for (let i = 0; i < numberOfSimulations; i++) {
|
|
98
|
+
const input = (0, input_clone_1.cloneInput3)(inputReady);
|
|
99
|
+
const inputClone = (0, input_clone_1.cloneInput3)(inputReady);
|
|
100
|
+
const gameState = {
|
|
101
|
+
allCards: cards,
|
|
102
|
+
cardsData: cardsData,
|
|
103
|
+
spectator: spectator,
|
|
104
|
+
sharedState: new shared_state_1.SharedState(),
|
|
105
|
+
currentTurn: input.gameState.currentTurn,
|
|
106
|
+
validTribes: input.gameState.validTribes,
|
|
107
|
+
anomalies: input.gameState.anomalies,
|
|
108
|
+
gameState: {
|
|
109
|
+
player: {
|
|
110
|
+
player: input.playerBoard.player,
|
|
111
|
+
board: input.playerBoard.board,
|
|
112
|
+
teammate: input.playerTeammateBoard,
|
|
113
|
+
},
|
|
114
|
+
opponent: {
|
|
115
|
+
player: input.opponentBoard.player,
|
|
116
|
+
board: input.opponentBoard.board,
|
|
117
|
+
teammate: input.opponentTeammateBoard,
|
|
118
|
+
},
|
|
119
|
+
playerInitial: {
|
|
120
|
+
player: inputClone.playerBoard.player,
|
|
121
|
+
board: inputClone.playerBoard.board,
|
|
122
|
+
teammate: inputClone.playerTeammateBoard,
|
|
123
|
+
},
|
|
124
|
+
opponentInitial: {
|
|
125
|
+
player: inputClone.opponentBoard.player,
|
|
126
|
+
board: inputClone.opponentBoard.board,
|
|
127
|
+
teammate: inputClone.opponentTeammateBoard,
|
|
128
|
+
},
|
|
110
129
|
},
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
if (!battleResult) {
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
if (battleResult.result === 'won') {
|
|
123
|
-
simulationResult.won++;
|
|
124
|
-
simulationResult.damageWon += battleResult.damageDealt;
|
|
125
|
-
simulationResult.damageWons.push(battleResult.damageDealt);
|
|
126
|
-
if (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {
|
|
127
|
-
simulationResult.wonLethal++;
|
|
130
|
+
};
|
|
131
|
+
const simulator = new simulator_1.Simulator(gameState);
|
|
132
|
+
const battleResult = simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);
|
|
133
|
+
if (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {
|
|
134
|
+
console.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');
|
|
135
|
+
break;
|
|
128
136
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
battleResult.damageDealt >= battleInput.
|
|
137
|
-
|
|
137
|
+
if (!battleResult) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (battleResult.result === 'won') {
|
|
141
|
+
simulationResult.won++;
|
|
142
|
+
simulationResult.damageWon += battleResult.damageDealt;
|
|
143
|
+
simulationResult.damageWons.push(battleResult.damageDealt);
|
|
144
|
+
if (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {
|
|
145
|
+
simulationResult.wonLethal++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (battleResult.result === 'lost') {
|
|
149
|
+
simulationResult.lost++;
|
|
150
|
+
simulationResult.damageLost += battleResult.damageDealt;
|
|
151
|
+
simulationResult.damageLosts.push(battleResult.damageDealt);
|
|
152
|
+
outcomes[battleResult.damageDealt] = ((_r = outcomes[battleResult.damageDealt]) !== null && _r !== void 0 ? _r : 0) + 1;
|
|
153
|
+
if (battleInput.playerBoard.player.hpLeft &&
|
|
154
|
+
battleResult.damageDealt >= battleInput.playerBoard.player.hpLeft) {
|
|
155
|
+
simulationResult.lostLethal++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (battleResult.result === 'tied') {
|
|
159
|
+
simulationResult.tied++;
|
|
160
|
+
}
|
|
161
|
+
spectator.commitBattleResult(battleResult.result);
|
|
162
|
+
if (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {
|
|
163
|
+
updateSimulationResult(simulationResult, inputReady, damageConfidence);
|
|
164
|
+
yield simulationResult;
|
|
138
165
|
}
|
|
139
166
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
spectator.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
167
|
+
updateSimulationResult(simulationResult, inputReady, damageConfidence);
|
|
168
|
+
!((_s = battleInput.options) === null || _s === void 0 ? void 0 : _s.skipInfoLogs) && console.timeEnd('simulation');
|
|
169
|
+
spectator.prune();
|
|
170
|
+
simulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);
|
|
171
|
+
simulationResult.damageWons = [];
|
|
172
|
+
simulationResult.damageLosts = [];
|
|
173
|
+
return simulationResult;
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
if (battleInput.debugState) {
|
|
177
|
+
debug_state_1.debugState.active = false;
|
|
147
178
|
}
|
|
148
179
|
}
|
|
149
|
-
updateSimulationResult(simulationResult, inputReady, damageConfidence);
|
|
150
|
-
!((_p = battleInput.options) === null || _p === void 0 ? void 0 : _p.skipInfoLogs) && console.timeEnd('simulation');
|
|
151
|
-
spectator.prune();
|
|
152
|
-
simulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);
|
|
153
|
-
simulationResult.damageWons = [];
|
|
154
|
-
simulationResult.damageLosts = [];
|
|
155
|
-
return simulationResult;
|
|
156
180
|
};
|
|
157
181
|
exports.simulateBattle = simulateBattle;
|
|
158
182
|
const updateSimulationResult = (simulationResult, input, damageConfidence) => {
|
|
@@ -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 { hasDeathrattleSpawnEnchantment } from './cards/card.interface';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { cardMappings } from './cards/impl/_card-mappings';\r\nimport { cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { CardIds } from './services/card-ids';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator } from './simulation/spectator/spectator';\r\n\r\nlet globalCards = new AllCardsService();\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\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}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tawait cards.initializeCardsDb();\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 (!cards?.getCards()?.length) {\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};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\tconst outcomes = {};\r\n\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\tconst input: BgsBattleInfo = cloneInput3(inputReady);\r\n\t\tconst inputClone: BgsBattleInfo = cloneInput3(inputReady);\r\n\t\tconst gameState: FullGameState = {\r\n\t\t\tallCards: cards,\r\n\t\t\tcardsData: cardsData,\r\n\t\t\tspectator: spectator,\r\n\t\t\tsharedState: new SharedState(),\r\n\t\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\t\tvalidTribes: input.gameState.validTribes,\r\n\t\t\tanomalies: input.gameState.anomalies,\r\n\t\t\tgameState: {\r\n\t\t\t\tplayer: {\r\n\t\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t\t},\r\n\t\t\t\topponent: {\r\n\t\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t\t},\r\n\t\t\t\tplayerInitial: {\r\n\t\t\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t\t\t},\r\n\t\t\t\topponentInitial: {\r\n\t\t\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t};\r\n\t\tconst simulator = new Simulator(gameState);\r\n\t\tconst battleResult = simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\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\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tif (!battleResult) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (battleResult.result === 'won') {\r\n\t\t\tsimulationResult.won++;\r\n\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\tsimulationResult.lost++;\r\n\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\tif (\r\n\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t) {\r\n\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\tsimulationResult.tied++;\r\n\t\t}\r\n\t\tspectator.commitBattleResult(battleResult.result);\r\n\r\n\t\t// Yield intermediate result every 200 iterations\r\n\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\tyield simulationResult;\r\n\t\t}\r\n\t}\r\n\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\tspectator.prune();\r\n\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t// Avoid sending this verbose data\r\n\r\n\tsimulationResult.damageWons = [];\r\n\tsimulationResult.damageLosts = [];\r\n\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\treturn simulationResult;\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// Used when triggering random deathrattles\r\nconst VALID_DEATHRATTLE_ENCHANTMENTS = [\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment_BG_BOT_312e,\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment_TB_BaconUps_032e,\r\n\tCardIds.LivingSpores_LivingSporesEnchantment,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000e,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000_Ge,\r\n\tCardIds.Sneed_SneedsReplicator,\r\n\tCardIds.SneedsReplicator_ReplicateEnchantment,\r\n\tCardIds.EarthRecollectionEnchantment, // Spirit Raptor\r\n\tCardIds.FireRecollectionEnchantment,\r\n\tCardIds.LightningRecollectionEnchantment,\r\n\tCardIds.WaterRecollectionEnchantment,\r\n\tCardIds.EarthInvocation_ElementEarthEnchantment, // Summon a 1/1\r\n\tCardIds.LightningInvocation, // Deal 1 damage to 5 enemy minions\r\n\t// CardIds.SurfNSurf_CrabRidingEnchantment_BG27_004e,\r\n\t// CardIds.SurfNSurf_CrabRidingEnchantment_BG27_004_Ge,\r\n\t// CardIds.RecurringNightmare_NightmareInsideEnchantment_BG26_055e,\r\n\t// CardIds.RecurringNightmare_NightmareInsideEnchantment_BG26_055_Ge,\r\n\tCardIds.BoonOfBeetles_BeetleSwarmEnchantment_BG28_603e,\r\n\tCardIds.RustyTrident_TridentsTreasureEnchantment_BG30_MagicItem_917e,\r\n\tCardIds.HoggyBank_GemInTheBankEnchantment_BG30_MagicItem_411e,\r\n\tCardIds.JarredFrostling_FrostyGlobeEnchantment_BG30_MagicItem_952e,\r\n\tCardIds.CaduceusReactor_CaduceusReactorEnchantment_BG31_HERO_801ptee,\r\n\tCardIds.AutoAssembler_AutoAssemblerEnchantment_BG32_172e,\r\n\tCardIds.AutoAssembler_AutoAssemblerEnchantment_BG32_172_Ge,\r\n\tCardIds.TamsinRoame_ImpendingSacrificeEnchantment_BG20_HERO_282e2,\r\n];\r\nconst validDeathrattleEnchantmentsFromMapping = [];\r\nexport const isValidDeathrattleEnchantment = (cardId: string): boolean => {\r\n\tif (VALID_DEATHRATTLE_ENCHANTMENTS.includes(cardId as CardIds)) {\r\n\t\treturn true;\r\n\t}\r\n\tif (validDeathrattleEnchantmentsFromMapping.length === 0) {\r\n\t\tfor (const cardImpl of Object.values(cardMappings)) {\r\n\t\t\t// Also includes non-enchantments, but since we only match this against the enchants list, it's fine\r\n\t\t\tif (hasDeathrattleSpawnEnchantment(cardImpl)) {\r\n\t\t\t\tvalidDeathrattleEnchantmentsFromMapping.push(...cardImpl.cardIds);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn validDeathrattleEnchantmentsFromMapping.includes(cardId);\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 */\nimport { AllCardsService } from '@firestone-hs/reference-data';\nimport { BgsBattleInfo } from './bgs-battle-info';\nimport { hasDeathrattleSpawnEnchantment } from './cards/card.interface';\nimport { CardsData } from './cards/cards-data';\nimport { cardMappings } from './cards/impl/_card-mappings';\nimport { debugState } from './debug-state';\nimport { cloneInput3 } from './input-clone';\nimport { buildFinalInput } from './input-sanitation';\nimport { CardIds } from './services/card-ids';\nimport { SimulationResult } from './simulation-result';\nimport { FullGameState } from './simulation/internal-game-state';\nimport { SharedState } from './simulation/shared-state';\nimport { Simulator } from './simulation/simulator';\nimport { Spectator } from './simulation/spectator/spectator';\n\nlet globalCards = new AllCardsService();\n\nexport const assignCards = (cards: AllCardsService) => {\n\tglobalCards = cards;\n};\n\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\n// the more traditional callback-style handler.\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\nexport default async (event): Promise<any> => {\n\tif (!event.body?.length) {\n\t\tconsole.warn('missing event body', event);\n\t\treturn;\n\t}\n\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\n\tconst cards = globalCards;\n\tawait cards.initializeCardsDb();\n\tconst cardsData = new CardsData(cards, false);\n\tcardsData.inititialize(\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\n\t\tbattleInput.gameState?.anomalies ?? [],\n\t);\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\n\n\t// Iterate through all intermediate results to reach the final result\n\tlet result = battleIterator.next();\n\twhile (!result.done) {\n\t\tresult = battleIterator.next();\n\t}\n\n\tconst simulationResult = result.value;\n\t// console.debug('simulationResult', simulationResult);\n\n\tconst response = {\n\t\tstatusCode: 200,\n\t\tisBase64Encoded: false,\n\t\tbody: JSON.stringify(simulationResult),\n\t};\n\treturn response;\n};\n\nexport const simulateBattle = function* (\n\tbattleInput: BgsBattleInfo,\n\tcards: AllCardsService,\n\tcardsData: CardsData,\n): Generator<SimulationResult, SimulationResult, void> {\n\tif (!cards?.getCards()?.length) {\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\n\t\treturn null;\n\t}\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\n\tconst start = Date.now();\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\n\tconst simulationResult: SimulationResult = {\n\t\twonLethal: 0,\n\t\twon: 0,\n\t\ttied: 0,\n\t\tlost: 0,\n\t\tlostLethal: 0,\n\t\tdamageWons: [],\n\t\tdamageWon: 0,\n\t\tdamageWonRange: null,\n\t\tdamageLosts: [],\n\t\tdamageLost: 0,\n\t\tdamageLostRange: null,\n\t\twonLethalPercent: undefined,\n\t\twonPercent: undefined,\n\t\ttiedPercent: undefined,\n\t\tlostPercent: undefined,\n\t\tlostLethalPercent: undefined,\n\t\taverageDamageWon: undefined,\n\t\taverageDamageLost: undefined,\n\t};\n\n\tconst spectator = new Spectator(includeOutcomeSamples);\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\n\n\t// Apply debug state from input when present (e.g. from bug report)\n\tif (battleInput.debugState) {\n\t\tdebugState.active = true;\n\t\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\n\t\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\n\t\t\tattacker: { ...f.attacker },\n\t\t\tdefender: { ...f.defender },\n\t\t}));\n\t\tconst rawPicks =\n\t\t\tbattleInput.debugState.forcedRandomPicks ??\n\t\t\tbattleInput.debugState.forcedTimewarpedWarghoulTargets?.map((target) => ({\n\t\t\t\tsource: { cardId: 'BG34_Giant_331' },\n\t\t\t\ttarget,\n\t\t\t})) ??\n\t\t\t[];\n\t\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\n\t\t\tsource: { ...p.source },\n\t\t\ttarget: { ...p.target },\n\t\t}));\n\t}\n\n\ttry {\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\n\t\tconst outcomes = {};\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\n\t\t\tconst input: BgsBattleInfo = cloneInput3(inputReady);\n\t\t\tconst inputClone: BgsBattleInfo = cloneInput3(inputReady);\n\t\t\tconst gameState: FullGameState = {\n\t\t\t\tallCards: cards,\n\t\t\t\tcardsData: cardsData,\n\t\t\t\tspectator: spectator,\n\t\t\t\tsharedState: new SharedState(),\n\t\t\t\tcurrentTurn: input.gameState.currentTurn,\n\t\t\t\tvalidTribes: input.gameState.validTribes,\n\t\t\t\tanomalies: input.gameState.anomalies,\n\t\t\t\tgameState: {\n\t\t\t\t\tplayer: {\n\t\t\t\t\t\tplayer: input.playerBoard.player,\n\t\t\t\t\t\tboard: input.playerBoard.board,\n\t\t\t\t\t\tteammate: input.playerTeammateBoard,\n\t\t\t\t\t},\n\t\t\t\t\topponent: {\n\t\t\t\t\t\tplayer: input.opponentBoard.player,\n\t\t\t\t\t\tboard: input.opponentBoard.board,\n\t\t\t\t\t\tteammate: input.opponentTeammateBoard,\n\t\t\t\t\t},\n\t\t\t\t\tplayerInitial: {\n\t\t\t\t\t\tplayer: inputClone.playerBoard.player,\n\t\t\t\t\t\tboard: inputClone.playerBoard.board,\n\t\t\t\t\t\tteammate: inputClone.playerTeammateBoard,\n\t\t\t\t\t},\n\t\t\t\t\topponentInitial: {\n\t\t\t\t\t\tplayer: inputClone.opponentBoard.player,\n\t\t\t\t\t\tboard: inputClone.opponentBoard.board,\n\t\t\t\t\t\tteammate: inputClone.opponentTeammateBoard,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t\tconst simulator = new Simulator(gameState);\n\t\t\tconst battleResult = simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\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\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!battleResult) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (battleResult.result === 'won') {\n\t\t\t\tsimulationResult.won++;\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\n\t\t\t\t\tsimulationResult.wonLethal++;\n\t\t\t\t}\n\t\t\t} else if (battleResult.result === 'lost') {\n\t\t\t\tsimulationResult.lost++;\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\n\t\t\t\tif (\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\n\t\t\t\t) {\n\t\t\t\t\tsimulationResult.lostLethal++;\n\t\t\t\t}\n\t\t\t} else if (battleResult.result === 'tied') {\n\t\t\t\tsimulationResult.tied++;\n\t\t\t}\n\t\t\tspectator.commitBattleResult(battleResult.result);\n\n\t\t\t// Yield intermediate result every 200 iterations\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\n\t\t\t\tyield simulationResult;\n\t\t\t}\n\t\t}\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\n\t\tspectator.prune();\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\n\t\t// Avoid sending this verbose data\n\n\t\tsimulationResult.damageWons = [];\n\t\tsimulationResult.damageLosts = [];\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\n\t\treturn simulationResult;\n\t} finally {\n\t\tif (battleInput.debugState) {\n\t\t\tdebugState.active = false;\n\t\t}\n\t}\n};\n\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\n\tsimulationResult.wonPercent = checkRounding(\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\n\t\tsimulationResult.won,\n\t\ttotalMatches,\n\t);\n\tsimulationResult.wonLethalPercent = checkRounding(\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\n\t\tsimulationResult.wonLethal,\n\t\ttotalMatches,\n\t);\n\tsimulationResult.lostPercent = checkRounding(\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\n\t\tsimulationResult.lost,\n\t\ttotalMatches,\n\t);\n\tsimulationResult.lostLethalPercent = checkRounding(\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\n\t\tsimulationResult.lostLethal,\n\t\ttotalMatches,\n\t);\n\tsimulationResult.tiedPercent = checkRounding(\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\n\t\tsimulationResult.tied,\n\t\ttotalMatches,\n\t);\n\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\n\n\tif (\n\t\tsimulationResult.averageDamageWon > 0 &&\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\n\t) {\n\t\tconsole.warn('average damage won issue');\n\t}\n\tif (\n\t\tsimulationResult.averageDamageLost > 0 &&\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\n\t) {\n\t\tconsole.warn('average damage lost issue');\n\t}\n};\n\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\n\tif (damageArray.length === 0) {\n\t\treturn { min: 0, max: 0 };\n\t}\n\n\t// Sort the array\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\n\n\t// Calculate the 10th and 90th percentiles\n\tconst percentile = (arr: number[], p: number) => {\n\t\tconst index = Math.floor(p * arr.length);\n\t\treturn arr[index];\n\t};\n\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\n\n\treturn { min: minDamage, max: maxDamage };\n};\n\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\n\tif (roundedValue === 0 && initialValue !== 0) {\n\t\treturn 0.01;\n\t}\n\tif (roundedValue === 100 && initialValue !== totalValue) {\n\t\treturn 99.9;\n\t}\n\treturn roundedValue;\n};\n\n// Used when triggering random deathrattles\nconst VALID_DEATHRATTLE_ENCHANTMENTS = [\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment_BG_BOT_312e,\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment_TB_BaconUps_032e,\n\tCardIds.LivingSpores_LivingSporesEnchantment,\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000e,\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000_Ge,\n\tCardIds.Sneed_SneedsReplicator,\n\tCardIds.SneedsReplicator_ReplicateEnchantment,\n\tCardIds.EarthRecollectionEnchantment, // Spirit Raptor\n\tCardIds.FireRecollectionEnchantment,\n\tCardIds.LightningRecollectionEnchantment,\n\tCardIds.WaterRecollectionEnchantment,\n\tCardIds.EarthInvocation_ElementEarthEnchantment, // Summon a 1/1\n\tCardIds.LightningInvocation, // Deal 1 damage to 5 enemy minions\n\t// CardIds.SurfNSurf_CrabRidingEnchantment_BG27_004e,\n\t// CardIds.SurfNSurf_CrabRidingEnchantment_BG27_004_Ge,\n\t// CardIds.RecurringNightmare_NightmareInsideEnchantment_BG26_055e,\n\t// CardIds.RecurringNightmare_NightmareInsideEnchantment_BG26_055_Ge,\n\tCardIds.BoonOfBeetles_BeetleSwarmEnchantment_BG28_603e,\n\tCardIds.RustyTrident_TridentsTreasureEnchantment_BG30_MagicItem_917e,\n\tCardIds.HoggyBank_GemInTheBankEnchantment_BG30_MagicItem_411e,\n\tCardIds.JarredFrostling_FrostyGlobeEnchantment_BG30_MagicItem_952e,\n\tCardIds.CaduceusReactor_CaduceusReactorEnchantment_BG31_HERO_801ptee,\n\tCardIds.AutoAssembler_AutoAssemblerEnchantment_BG32_172e,\n\tCardIds.AutoAssembler_AutoAssemblerEnchantment_BG32_172_Ge,\n\tCardIds.TamsinRoame_ImpendingSacrificeEnchantment_BG20_HERO_282e2,\n];\nconst validDeathrattleEnchantmentsFromMapping = [];\nexport const isValidDeathrattleEnchantment = (cardId: string): boolean => {\n\tif (VALID_DEATHRATTLE_ENCHANTMENTS.includes(cardId as CardIds)) {\n\t\treturn true;\n\t}\n\tif (validDeathrattleEnchantmentsFromMapping.length === 0) {\n\t\tfor (const cardImpl of Object.values(cardMappings)) {\n\t\t\t// Also includes non-enchantments, but since we only match this against the enchants list, it's fine\n\t\t\tif (hasDeathrattleSpawnEnchantment(cardImpl)) {\n\t\t\t\tvalidDeathrattleEnchantmentsFromMapping.push(...cardImpl.cardIds);\n\t\t\t}\n\t\t}\n\t}\n\treturn validDeathrattleEnchantmentsFromMapping.includes(cardId);\n};\n\n// const cleanEnchantmentsForEntity = (\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\n// \tentityIds: readonly number[],\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\n// \treturn enchantments.filter(\n// \t\t(enchant) =>\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\n// \t);\n// };\n"]}
|
|
@@ -5,7 +5,6 @@ const utils_1 = require("../utils");
|
|
|
5
5
|
const add_minion_to_board_1 = require("./add-minion-to-board");
|
|
6
6
|
const deathrattle_spawns_1 = require("./deathrattle-spawns");
|
|
7
7
|
const spawns_1 = require("./spawns");
|
|
8
|
-
const stats_1 = require("./stats");
|
|
9
8
|
const handleSplittingImage = (defendingEntity, defendingBoard, defendingPlayerEntity, attackerBoard, attackerHero, gameState) => {
|
|
10
9
|
const copy = {
|
|
11
10
|
...defendingEntity,
|
|
@@ -23,7 +22,12 @@ const handlePackTactics = (defendingEntity, defendingBoard, defendingPlayerEntit
|
|
|
23
22
|
(0, add_minion_to_board_1.removeAurasFromSelf)(copy, defendingBoard, defendingPlayerEntity, gameState);
|
|
24
23
|
const candidateEntities = (0, deathrattle_spawns_1.spawnEntities)(copy.cardId, 1, defendingBoard, defendingPlayerEntity, attackerBoard, attackerHero, gameState, defendingEntity.friendly, false, false, true, copy);
|
|
25
24
|
if (secretCardId === "TB_Bacon_Secrets_15") {
|
|
26
|
-
candidateEntities.forEach((e) =>
|
|
25
|
+
candidateEntities.forEach((e) => {
|
|
26
|
+
e.health = 3;
|
|
27
|
+
e.maxHealth = 3;
|
|
28
|
+
e.attack = 3;
|
|
29
|
+
e.maxAttack = 3;
|
|
30
|
+
});
|
|
27
31
|
}
|
|
28
32
|
const indexFromRight = defendingBoard.length - (defendingBoard.indexOf(defendingEntity) + 1);
|
|
29
33
|
const spawned = (0, spawns_1.performEntitySpawns)(candidateEntities, defendingBoard, defendingPlayerEntity, defendingEntity, indexFromRight, attackerBoard, attackerHero, gameState);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/simulation/secrets.ts"],"names":[],"mappings":";;;AAGA,oCAAsC;AACtC,+DAA4D;AAC5D,6DAAqD;AAErD,qCAA+C;
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/simulation/secrets.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { copyEntity } from '../utils';\r\nimport { removeAurasFromSelf } from './add-minion-to-board';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\n\r\nexport const handleSplittingImage = (\r\n\tdefendingEntity: BoardEntity,\r\n\tdefendingBoard: BoardEntity[],\r\n\tdefendingPlayerEntity: BgsPlayerEntity,\r\n\tattackerBoard: BoardEntity[],\r\n\tattackerHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst copy: BoardEntity = {\r\n\t\t...defendingEntity,\r\n\t\tattack: 3,\r\n\t\thealth: 3,\r\n\t\tmaxHealth: 3,\r\n\t};\r\n\tconst candidateEntities = spawnEntities(\r\n\t\tdefendingEntity.cardId,\r\n\t\t1,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t\tdefendingEntity.friendly,\r\n\t\tfalse,\r\n\t\tfalse,\r\n\t\ttrue,\r\n\t\tcopy,\r\n\t);\r\n\tconst indexFromRight = defendingBoard.length - (defendingBoard.indexOf(defendingEntity) + 1);\r\n\tperformEntitySpawns(\r\n\t\tcandidateEntities,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tdefendingEntity,\r\n\t\tindexFromRight,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t);\r\n};\r\n\r\nexport const handlePackTactics = (\r\n\tdefendingEntity: BoardEntity,\r\n\tdefendingBoard: BoardEntity[],\r\n\tdefendingPlayerEntity: BgsPlayerEntity,\r\n\tattackerBoard: BoardEntity[],\r\n\tattackerHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tsecretCardId: string,\r\n): void => {\r\n\tconst copy: BoardEntity = copyEntity(defendingEntity);\r\n\tremoveAurasFromSelf(copy, defendingBoard, defendingPlayerEntity, gameState);\r\n\tconst candidateEntities = spawnEntities(\r\n\t\tcopy.cardId,\r\n\t\t1,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t\tdefendingEntity.friendly,\r\n\t\tfalse,\r\n\t\tfalse,\r\n\t\ttrue,\r\n\t\tcopy,\r\n\t);\r\n\tif (secretCardId === CardIds.PackTactics_TB_Bacon_Secrets_15) {\r\n\t\t// Don't use setEntityStats, because it will be applied when adding the minion to the board\r\n\t\tcandidateEntities.forEach((e) => {\r\n\t\t\te.health = 3;\r\n\t\t\te.maxHealth = 3;\r\n\t\t\te.attack = 3;\r\n\t\t\te.maxAttack = 3;\r\n\t\t});\r\n\t\t//setEntityStats(e, 3, 3, defendingBoard, defendingPlayerEntity, gameState));\r\n\t}\r\n\tconst indexFromRight = defendingBoard.length - (defendingBoard.indexOf(defendingEntity) + 1);\r\n\tconst spawned = performEntitySpawns(\r\n\t\tcandidateEntities,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tdefendingEntity,\r\n\t\tindexFromRight,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t);\r\n\tspawned.forEach((e) => {\r\n\t\t// Might be a HS bug\r\n\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=06e89a29-8f63-4c55-bdac-d908ed6e5857&turn=9&action=1\r\n\t\te.hasAttacked = defendingEntity.hasAttacked;\r\n\t});\r\n};\r\n\r\nexport const handleSnakeTrap = (\r\n\tdefendingEntity: BoardEntity,\r\n\tdefendingBoard: BoardEntity[],\r\n\tdefendingPlayerEntity: BgsPlayerEntity,\r\n\tattackerBoard: BoardEntity[],\r\n\tattackerHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst candidateEntities: readonly BoardEntity[] = spawnEntities(\r\n\t\tCardIds.SnakeTrap_SnakeLegacyToken,\r\n\t\t3,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t\tdefendingEntity.friendly,\r\n\t\tfalse,\r\n\t);\r\n\tperformEntitySpawns(\r\n\t\tcandidateEntities,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tdefendingEntity,\r\n\t\t0,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t);\r\n};\r\n\r\nexport const handleVenomstrikeTrap = (\r\n\tdefendingEntity: BoardEntity,\r\n\tdefendingBoard: BoardEntity[],\r\n\tdefendingPlayerEntity: BgsPlayerEntity,\r\n\tattackerBoard: BoardEntity[],\r\n\tattackerHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tconst candidateEntities: readonly BoardEntity[] = spawnEntities(\r\n\t\tCardIds.EmperorCobraLegacy_BG_EX1_170,\r\n\t\t1,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t\tdefendingEntity.friendly,\r\n\t\tfalse,\r\n\t);\r\n\tconst spawns = performEntitySpawns(\r\n\t\tcandidateEntities,\r\n\t\tdefendingBoard,\r\n\t\tdefendingPlayerEntity,\r\n\t\tdefendingEntity,\r\n\t\t0,\r\n\t\tattackerBoard,\r\n\t\tattackerHero,\r\n\t\tgameState,\r\n\t);\r\n\treturn spawns;\r\n};\r\n"]}
|