@firestone-hs/simulate-bgs-battle 1.1.721 → 1.1.723
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/cards/card.interface.d.ts +4 -0
- package/dist/cards/card.interface.js +4 -2
- package/dist/cards/card.interface.js.map +1 -1
- package/dist/cards/impl/_card-mappings.js +2 -0
- package/dist/cards/impl/_card-mappings.js.map +1 -1
- package/dist/cards/impl/hero-power/lightning-invocation.js +4 -1
- package/dist/cards/impl/hero-power/lightning-invocation.js.map +1 -1
- package/dist/cards/impl/minion/glowing-cinder.js +1 -1
- package/dist/cards/impl/minion/glowing-cinder.js.map +1 -1
- package/dist/cards/impl/minion/sanguine-refiner.js +1 -1
- package/dist/cards/impl/minion/sanguine-refiner.js.map +1 -1
- package/dist/cards/impl/minion/silky-shimmermoth.js +5 -3
- package/dist/cards/impl/minion/silky-shimmermoth.js.map +1 -1
- package/dist/cards/impl/minion/timewarped-embalmer.d.ts +2 -2
- package/dist/cards/impl/minion/timewarped-embalmer.js +5 -1
- package/dist/cards/impl/minion/timewarped-embalmer.js.map +1 -1
- package/dist/cards/impl/minion/timewarped-pagle.d.ts +2 -0
- package/dist/cards/impl/minion/timewarped-pagle.js +15 -0
- package/dist/cards/impl/minion/timewarped-pagle.js.map +1 -0
- package/dist/cards/impl/minion/vinespeaker.js +1 -1
- package/dist/cards/impl/minion/vinespeaker.js.map +1 -1
- package/dist/cards/impl/trinket/archaic-scroll.js +3 -2
- package/dist/cards/impl/trinket/archaic-scroll.js.map +1 -1
- package/dist/cards/impl/trinket/beetle-band.js +1 -1
- package/dist/cards/impl/trinket/beetle-band.js.map +1 -1
- package/dist/cards/impl/trinket/bubble-crown.js +2 -1
- package/dist/cards/impl/trinket/bubble-crown.js.map +1 -1
- package/dist/cards/impl/trinket/deathtouch-apple.js.map +1 -1
- package/dist/cards/impl/trinket/quilligraphy-set.js +1 -1
- package/dist/cards/impl/trinket/quilligraphy-set.js.map +1 -1
- package/dist/input-clone.d.ts +1 -0
- package/dist/input-clone.js +13 -1
- package/dist/input-clone.js.map +1 -1
- package/dist/mechanics/rally.js +14 -12
- package/dist/mechanics/rally.js.map +1 -1
- package/dist/mechanics/tavern-spell-repeat.js +3 -4
- package/dist/mechanics/tavern-spell-repeat.js.map +1 -1
- package/dist/simulate-bgs-battle.d.ts +1 -1
- package/dist/simulate-bgs-battle.js +80 -77
- package/dist/simulate-bgs-battle.js.map +1 -1
- package/dist/simulation/add-minion-to-board.js +3 -3
- package/dist/simulation/add-minion-to-board.js.map +1 -1
- package/dist/simulation/attack.js +3 -3
- package/dist/simulation/attack.js.map +1 -1
- package/dist/simulation/avenge.js +2 -2
- package/dist/simulation/avenge.js.map +1 -1
- package/dist/simulation/deathrattle-effects.js +48 -14
- package/dist/simulation/deathrattle-effects.js.map +1 -1
- package/dist/simulation/deathrattle-spawns.js +19 -12
- package/dist/simulation/deathrattle-spawns.js.map +1 -1
- package/dist/simulation/deathrattle-utils.d.ts +1 -0
- package/dist/simulation/deathrattle-utils.js +45 -5
- package/dist/simulation/deathrattle-utils.js.map +1 -1
- package/dist/simulation/on-attack.js +13 -14
- package/dist/simulation/on-attack.js.map +1 -1
- package/dist/simulation/reborn.js +11 -0
- package/dist/simulation/reborn.js.map +1 -1
- package/dist/simulation/simulator.d.ts +1 -0
- package/dist/simulation/simulator.js +39 -74
- package/dist/simulation/simulator.js.map +1 -1
- package/dist/simulation/spectator/resolve-trinket-hero-power.js +11 -2
- package/dist/simulation/spectator/resolve-trinket-hero-power.js.map +1 -1
- package/dist/simulation/spectator/spectator.d.ts +4 -0
- package/dist/simulation/spectator/spectator.js +39 -19
- package/dist/simulation/spectator/spectator.js.map +1 -1
- package/dist/simulation/stats.js +95 -66
- package/dist/simulation/stats.js.map +1 -1
- package/dist/simulation/summon-when-space.js +24 -21
- package/dist/simulation/summon-when-space.js.map +1 -1
- package/dist/utils.js +89 -48
- package/dist/utils.js.map +1 -1
- package/package.json +3 -2
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.simulateBattle = exports.assignCards = exports.isValidDeathrattleEnchantment = void 0;
|
|
4
4
|
const reference_data_1 = require("@firestone-hs/reference-data");
|
|
5
|
-
const card_interface_1 = require("./cards/card.interface");
|
|
6
5
|
const cards_data_1 = require("./cards/cards-data");
|
|
7
|
-
const _card_mappings_1 = require("./cards/impl/_card-mappings");
|
|
8
6
|
const debug_state_1 = require("./debug-state");
|
|
9
7
|
const input_clone_1 = require("./input-clone");
|
|
10
8
|
const input_sanitation_1 = require("./input-sanitation");
|
|
11
9
|
const shared_state_1 = require("./simulation/shared-state");
|
|
12
10
|
const simulator_1 = require("./simulation/simulator");
|
|
13
11
|
const spectator_1 = require("./simulation/spectator/spectator");
|
|
12
|
+
var deathrattle_utils_1 = require("./simulation/deathrattle-utils");
|
|
13
|
+
Object.defineProperty(exports, "isValidDeathrattleEnchantment", { enumerable: true, get: function () { return deathrattle_utils_1.isValidDeathrattleEnchantment; } });
|
|
14
|
+
const MAX_SAMPLE_RESIMS = 500;
|
|
14
15
|
let globalCards = new reference_data_1.AllCardsService();
|
|
15
16
|
const assignCards = (cards) => {
|
|
16
17
|
globalCards = cards;
|
|
@@ -89,45 +90,65 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
89
90
|
...(p.chosenCardId && { chosenCardId: p.chosenCardId }),
|
|
90
91
|
}));
|
|
91
92
|
}
|
|
93
|
+
const cloneTemplate = (0, input_clone_1.buildTemplateCloner)((0, input_clone_1.cloneInput3)(inputReady));
|
|
94
|
+
const runSingleBattle = () => {
|
|
95
|
+
const input = cloneTemplate();
|
|
96
|
+
let playerInitialState = null;
|
|
97
|
+
let opponentInitialState = null;
|
|
98
|
+
const buildInitialStates = () => {
|
|
99
|
+
const inputClone = cloneTemplate();
|
|
100
|
+
playerInitialState = {
|
|
101
|
+
player: inputClone.playerBoard.player,
|
|
102
|
+
board: inputClone.playerBoard.board,
|
|
103
|
+
teammate: inputClone.playerTeammateBoard,
|
|
104
|
+
};
|
|
105
|
+
opponentInitialState = {
|
|
106
|
+
player: inputClone.opponentBoard.player,
|
|
107
|
+
board: inputClone.opponentBoard.board,
|
|
108
|
+
teammate: inputClone.opponentTeammateBoard,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
const gameState = {
|
|
112
|
+
allCards: cards,
|
|
113
|
+
cardsData: cardsData,
|
|
114
|
+
spectator: spectator,
|
|
115
|
+
sharedState: new shared_state_1.SharedState(),
|
|
116
|
+
currentTurn: input.gameState.currentTurn,
|
|
117
|
+
validTribes: input.gameState.validTribes,
|
|
118
|
+
anomalies: input.gameState.anomalies,
|
|
119
|
+
gameState: {
|
|
120
|
+
player: {
|
|
121
|
+
player: input.playerBoard.player,
|
|
122
|
+
board: input.playerBoard.board,
|
|
123
|
+
teammate: input.playerTeammateBoard,
|
|
124
|
+
},
|
|
125
|
+
opponent: {
|
|
126
|
+
player: input.opponentBoard.player,
|
|
127
|
+
board: input.opponentBoard.board,
|
|
128
|
+
teammate: input.opponentTeammateBoard,
|
|
129
|
+
},
|
|
130
|
+
get playerInitial() {
|
|
131
|
+
if (!playerInitialState) {
|
|
132
|
+
buildInitialStates();
|
|
133
|
+
}
|
|
134
|
+
return playerInitialState;
|
|
135
|
+
},
|
|
136
|
+
get opponentInitial() {
|
|
137
|
+
if (!opponentInitialState) {
|
|
138
|
+
buildInitialStates();
|
|
139
|
+
}
|
|
140
|
+
return opponentInitialState;
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
const simulator = new simulator_1.Simulator(gameState);
|
|
145
|
+
return simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);
|
|
146
|
+
};
|
|
92
147
|
try {
|
|
93
148
|
!((_o = battleInput.options) === null || _o === void 0 ? void 0 : _o.skipInfoLogs) && console.time('simulation');
|
|
94
149
|
const outcomes = {};
|
|
95
150
|
for (let i = 0; i < numberOfSimulations; i++) {
|
|
96
|
-
const
|
|
97
|
-
const inputClone = (0, input_clone_1.cloneInput3)(inputReady);
|
|
98
|
-
const gameState = {
|
|
99
|
-
allCards: cards,
|
|
100
|
-
cardsData: cardsData,
|
|
101
|
-
spectator: spectator,
|
|
102
|
-
sharedState: new shared_state_1.SharedState(),
|
|
103
|
-
currentTurn: input.gameState.currentTurn,
|
|
104
|
-
validTribes: input.gameState.validTribes,
|
|
105
|
-
anomalies: input.gameState.anomalies,
|
|
106
|
-
gameState: {
|
|
107
|
-
player: {
|
|
108
|
-
player: input.playerBoard.player,
|
|
109
|
-
board: input.playerBoard.board,
|
|
110
|
-
teammate: input.playerTeammateBoard,
|
|
111
|
-
},
|
|
112
|
-
opponent: {
|
|
113
|
-
player: input.opponentBoard.player,
|
|
114
|
-
board: input.opponentBoard.board,
|
|
115
|
-
teammate: input.opponentTeammateBoard,
|
|
116
|
-
},
|
|
117
|
-
playerInitial: {
|
|
118
|
-
player: inputClone.playerBoard.player,
|
|
119
|
-
board: inputClone.playerBoard.board,
|
|
120
|
-
teammate: inputClone.playerTeammateBoard,
|
|
121
|
-
},
|
|
122
|
-
opponentInitial: {
|
|
123
|
-
player: inputClone.opponentBoard.player,
|
|
124
|
-
board: inputClone.opponentBoard.board,
|
|
125
|
-
teammate: inputClone.opponentTeammateBoard,
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
const simulator = new simulator_1.Simulator(gameState);
|
|
130
|
-
const battleResult = simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);
|
|
151
|
+
const battleResult = runSingleBattle();
|
|
131
152
|
if (!battleResult) {
|
|
132
153
|
continue;
|
|
133
154
|
}
|
|
@@ -152,7 +173,6 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
152
173
|
else if (battleResult.result === 'tied') {
|
|
153
174
|
simulationResult.tied++;
|
|
154
175
|
}
|
|
155
|
-
spectator.commitBattleResult(battleResult.result);
|
|
156
176
|
if (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {
|
|
157
177
|
console.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');
|
|
158
178
|
break;
|
|
@@ -164,6 +184,27 @@ const simulateBattle = function* (battleInput, cards, cardsData) {
|
|
|
164
184
|
}
|
|
165
185
|
updateSimulationResult(simulationResult, inputReady, damageConfidence);
|
|
166
186
|
!((_q = battleInput.options) === null || _q === void 0 ? void 0 : _q.skipInfoLogs) && console.timeEnd('simulation');
|
|
187
|
+
if (includeOutcomeSamples) {
|
|
188
|
+
const neededOutcomes = [];
|
|
189
|
+
simulationResult.won > 0 && neededOutcomes.push('won');
|
|
190
|
+
simulationResult.lost > 0 && neededOutcomes.push('lost');
|
|
191
|
+
simulationResult.tied > 0 && neededOutcomes.push('tied');
|
|
192
|
+
const missingOutcomes = new Set(neededOutcomes);
|
|
193
|
+
if (missingOutcomes.size > 0) {
|
|
194
|
+
spectator.startRecording();
|
|
195
|
+
for (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {
|
|
196
|
+
const battleResult = runSingleBattle();
|
|
197
|
+
if (!(battleResult === null || battleResult === void 0 ? void 0 : battleResult.result)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
spectator.commitBattleResult(battleResult.result);
|
|
201
|
+
if (spectator.hasSampleFor(battleResult.result)) {
|
|
202
|
+
missingOutcomes.delete(battleResult.result);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
spectator.stopRecording();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
167
208
|
spectator.prune();
|
|
168
209
|
simulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);
|
|
169
210
|
simulationResult.damageWons = [];
|
|
@@ -223,42 +264,4 @@ const checkRounding = (roundedValue, initialValue, totalValue) => {
|
|
|
223
264
|
}
|
|
224
265
|
return roundedValue;
|
|
225
266
|
};
|
|
226
|
-
const VALID_DEATHRATTLE_ENCHANTMENTS = [
|
|
227
|
-
"BG_BOT_312e",
|
|
228
|
-
"TB_BaconUps_032e",
|
|
229
|
-
"UNG_999t2e",
|
|
230
|
-
"BG21_000e",
|
|
231
|
-
"BG21_000_Ge",
|
|
232
|
-
"BG21_HERO_030p",
|
|
233
|
-
"BG21_HERO_030pe",
|
|
234
|
-
"BG22_HERO_001_Buddy_e1",
|
|
235
|
-
"BG22_HERO_001_Buddy_e2",
|
|
236
|
-
"BG22_HERO_001_Buddy_e4",
|
|
237
|
-
"BG22_HERO_001_Buddy_e3",
|
|
238
|
-
"BG22_HERO_001p_t1e",
|
|
239
|
-
"BG22_HERO_001p_t4_s",
|
|
240
|
-
"BG28_603e",
|
|
241
|
-
"BG30_MagicItem_917e",
|
|
242
|
-
"BG30_MagicItem_411e",
|
|
243
|
-
"BG30_MagicItem_952e",
|
|
244
|
-
"BG31_HERO_801ptee",
|
|
245
|
-
"BG32_172e",
|
|
246
|
-
"BG32_172_Ge",
|
|
247
|
-
"BG20_HERO_282e2",
|
|
248
|
-
];
|
|
249
|
-
const validDeathrattleEnchantmentsFromMapping = [];
|
|
250
|
-
const isValidDeathrattleEnchantment = (cardId) => {
|
|
251
|
-
if (VALID_DEATHRATTLE_ENCHANTMENTS.includes(cardId)) {
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
if (validDeathrattleEnchantmentsFromMapping.length === 0) {
|
|
255
|
-
for (const cardImpl of Object.values(_card_mappings_1.cardMappings)) {
|
|
256
|
-
if ((0, card_interface_1.hasDeathrattleSpawnEnchantment)(cardImpl)) {
|
|
257
|
-
validDeathrattleEnchantmentsFromMapping.push(...cardImpl.cardIds);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return validDeathrattleEnchantmentsFromMapping.includes(cardId);
|
|
262
|
-
};
|
|
263
|
-
exports.isValidDeathrattleEnchantment = isValidDeathrattleEnchantment;
|
|
264
267
|
//# sourceMappingURL=simulate-bgs-battle.js.map
|
|
@@ -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 { debugState } from './debug-state';\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\r\n\t// Apply debug state from input when present (e.g. from bug report)\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = true;\r\n\t\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\t\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\r\n\t\t\tattacker: { ...f.attacker },\r\n\t\t\tdefender: { ...f.defender },\r\n\t\t}));\r\n\t\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\t\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\t\tsource: { ...p.source },\r\n\t\t\ttarget: { ...p.target },\r\n\t\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t\t}));\r\n\t}\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 input: BgsBattleInfo = cloneInput3(inputReady);\r\n\t\t\tconst inputClone: BgsBattleInfo = cloneInput3(inputReady);\r\n\t\t\tconst gameState: FullGameState = {\r\n\t\t\t\tallCards: cards,\r\n\t\t\t\tcardsData: cardsData,\r\n\t\t\t\tspectator: spectator,\r\n\t\t\t\tsharedState: new SharedState(),\r\n\t\t\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\t\t\tvalidTribes: input.gameState.validTribes,\r\n\t\t\t\tanomalies: input.gameState.anomalies,\r\n\t\t\t\tgameState: {\r\n\t\t\t\t\tplayer: {\r\n\t\t\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t\t\t},\r\n\t\t\t\t\topponent: {\r\n\t\t\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t\t\t},\r\n\t\t\t\t\tplayerInitial: {\r\n\t\t\t\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\t\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\t\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t\t\t\t},\r\n\t\t\t\t\topponentInitial: {\r\n\t\t\t\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\t\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\t\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t\t\t\t},\r\n\t\t\t\t},\r\n\t\t\t};\r\n\t\t\tconst simulator = new Simulator(gameState);\r\n\t\t\tconst battleResult = simulator.simulateSingleBattle(\r\n\t\t\t\tgameState.gameState.player,\r\n\t\t\t\tgameState.gameState.opponent,\r\n\t\t\t);\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\t\t\tspectator.commitBattleResult(battleResult.result);\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\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\tif (battleInput.debugState) {\r\n\t\t\tdebugState.active = false;\r\n\t\t}\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// 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":";;;AACA,iEAA+D;AAE/D,mDAA+C;AAC/C,+CAA2C;AAC3C,+CAAiE;AACjE,yDAAqD;AAGrD,4DAAwD;AACxD,sDAAmD;AACnD,gEAA6D;AAE7D,oEAA+E;AAAtE,kIAAA,6BAA6B,OAAA;AAKtC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,IAAI,WAAW,GAAG,IAAI,gCAAe,EAAE,CAAC;AAEjC,MAAM,WAAW,GAAG,CAAC,KAAsB,EAAE,EAAE;IACrD,WAAW,GAAG,KAAK,CAAC;AACrB,CAAC,CAAC;AAFW,QAAA,WAAW,eAEtB;AAKF,kBAAe,KAAK,EAAE,KAAK,EAAgB,EAAE;;IAC5C,IAAI,CAAC,CAAA,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAA,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO;KACP;IAED,MAAM,WAAW,GAAkB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,WAAW,CAAC;IAC1B,MAAM,KAAK,CAAC,iBAAiB,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,sBAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9C,SAAS,CAAC,YAAY,CACrB,MAAA,MAAA,WAAW,CAAC,SAAS,0CAAE,WAAW,mCAAI,MAAA,WAAW,CAAC,OAAO,0CAAE,WAAW,EACtE,MAAA,MAAA,WAAW,CAAC,SAAS,0CAAE,SAAS,mCAAI,EAAE,CACtC,CAAC;IACF,MAAM,cAAc,GAAG,IAAA,sBAAc,EAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAGrE,IAAI,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;IACnC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE;QACpB,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;KAC/B;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;IAGtC,MAAM,QAAQ,GAAG;QAChB,UAAU,EAAE,GAAG;QACf,eAAe,EAAE,KAAK;QACtB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;KACtC,CAAC;IACF,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAEK,MAAM,cAAc,GAAG,QAAQ,CAAC,EACtC,WAA0B,EAC1B,KAAsB,EACtB,SAAoB;;IAEpB,IAAI,CAAC,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,QAAQ,EAAE,0CAAE,MAAM,CAAA,EAAE;QAC/B,OAAO,CAAC,KAAK,CAAC,yEAAyE,EAAE,KAAK,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC;KACZ;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,qBAAqB,GAAG,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,qBAAqB,KAAI,IAAI,CAAC;IACjF,MAAM,gCAAgC,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,gCAAgC,mCAAI,KAAK,CAAC;IACxG,MAAM,mBAAmB,GAAG,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,mBAAmB,KAAI,IAAI,CAAC;IAC7E,MAAM,iBAAiB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,mBAAmB,mCAAI,GAAG,CAAC;IAC1E,MAAM,gBAAgB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,gBAAgB,mCAAI,GAAG,CAAC;IACtE,MAAM,qBAAqB,GAAG,MAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,qBAAqB,mCAAI,IAAI,CAAC;IACjF,MAAM,gBAAgB,GAAqB;QAC1C,SAAS,EAAE,CAAC;QACZ,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CAAC;QACP,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,CAAC;QACZ,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,EAAE;QACf,UAAU,EAAE,CAAC;QACb,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,SAAS;QAC3B,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,SAAS;QACtB,iBAAiB,EAAE,SAAS;QAC5B,gBAAgB,EAAE,SAAS;QAC3B,iBAAiB,EAAE,SAAS;KAC5B,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,qBAAqB,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAA,kCAAe,EAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAGlE,IAAI,WAAW,CAAC,UAAU,EAAE;QAC3B,wBAAU,CAAC,MAAM,GAAG,IAAI,CAAC;QACzB,wBAAU,CAAC,qBAAqB,GAAG,WAAW,CAAC,UAAU,CAAC,qBAAqB,CAAC;QAChF,wBAAU,CAAC,iBAAiB,GAAG,WAAW,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnF,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;YAC3B,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;SAC3B,CAAC,CAAC,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAA,WAAW,CAAC,UAAU,CAAC,iBAAiB,mCAAI,EAAE,CAAC;QAChE,wBAAU,CAAC,qBAAqB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvD,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;YACvB,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;YACvB,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC;SACvD,CAAC,CAAC,CAAC;KACJ;IAOD,MAAM,aAAa,GAAG,IAAA,iCAAmB,EAAC,IAAA,yBAAW,EAAC,UAAU,CAAC,CAAC,CAAC;IAEnE,MAAM,eAAe,GAAG,GAAG,EAAE;QAC5B,MAAM,KAAK,GAAkB,aAAa,EAAE,CAAC;QAG7C,IAAI,kBAAkB,GAAG,IAAI,CAAC;QAC9B,IAAI,oBAAoB,GAAG,IAAI,CAAC;QAChC,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC/B,MAAM,UAAU,GAAkB,aAAa,EAAE,CAAC;YAClD,kBAAkB,GAAG;gBACpB,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM;gBACrC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK;gBACnC,QAAQ,EAAE,UAAU,CAAC,mBAAmB;aACxC,CAAC;YACF,oBAAoB,GAAG;gBACtB,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,MAAM;gBACvC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,KAAK;gBACrC,QAAQ,EAAE,UAAU,CAAC,qBAAqB;aAC1C,CAAC;QACH,CAAC,CAAC;QACF,MAAM,SAAS,GAAkB;YAChC,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,SAAS;YACpB,WAAW,EAAE,IAAI,0BAAW,EAAE;YAC9B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;YACxC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;YACxC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS;YACpC,SAAS,EAAE;gBACV,MAAM,EAAE;oBACP,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;oBAChC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,KAAK;oBAC9B,QAAQ,EAAE,KAAK,CAAC,mBAAmB;iBACnC;gBACD,QAAQ,EAAE;oBACT,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,MAAM;oBAClC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK;oBAChC,QAAQ,EAAE,KAAK,CAAC,qBAAqB;iBACrC;gBACD,IAAI,aAAa;oBAChB,IAAI,CAAC,kBAAkB,EAAE;wBACxB,kBAAkB,EAAE,CAAC;qBACrB;oBACD,OAAO,kBAAkB,CAAC;gBAC3B,CAAC;gBACD,IAAI,eAAe;oBAClB,IAAI,CAAC,oBAAoB,EAAE;wBAC1B,kBAAkB,EAAE,CAAC;qBACrB;oBACD,OAAO,oBAAoB,CAAC;gBAC7B,CAAC;aACD;SACD,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,SAAS,CAAC,oBAAoB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjG,CAAC,CAAC;IAEF,IAAI;QACH,CAAC,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,YAAY,CAAA,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,mBAAmB,EAAE,CAAC,EAAE,EAAE;YAC7C,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;YACvC,IAAI,CAAC,YAAY,EAAE;gBAClB,SAAS;aACT;YACD,IAAI,YAAY,CAAC,MAAM,KAAK,KAAK,EAAE;gBAClC,gBAAgB,CAAC,GAAG,EAAE,CAAC;gBACvB,gBAAgB,CAAC,SAAS,IAAI,YAAY,CAAC,WAAW,CAAC;gBACvD,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC3D,IAAI,YAAY,CAAC,WAAW,IAAI,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE;oBACxE,gBAAgB,CAAC,SAAS,EAAE,CAAC;iBAC7B;aACD;iBAAM,IAAI,YAAY,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC1C,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBACxB,gBAAgB,CAAC,UAAU,IAAI,YAAY,CAAC,WAAW,CAAC;gBACxD,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC5D,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,MAAA,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC,mCAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnF,IACC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM;oBACrC,YAAY,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAChE;oBACD,gBAAgB,CAAC,UAAU,EAAE,CAAC;iBAC9B;aACD;iBAAM,IAAI,YAAY,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC1C,gBAAgB,CAAC,IAAI,EAAE,CAAC;aACxB;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,qBAAqB,IAAI,CAAC,gCAAgC,EAAE;gBAEpF,OAAO,CAAC,IAAI,CAAC,2BAA2B,EAAE,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC;gBAC1F,MAAM;aACN;YAGD,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,iBAAiB,KAAK,CAAC,EAAE;gBAChE,sBAAsB,CAAC,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;gBACvE,MAAM,gBAAgB,CAAC;aACvB;SACD;QACD,sBAAsB,CAAC,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QACvE,CAAC,CAAA,MAAA,WAAW,CAAC,OAAO,0CAAE,YAAY,CAAA,IAAI,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAOpE,IAAI,qBAAqB,EAAE;YAC1B,MAAM,cAAc,GAAgC,EAAE,CAAC;YACvD,gBAAgB,CAAC,GAAG,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvD,gBAAgB,CAAC,IAAI,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzD,gBAAgB,CAAC,IAAI,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;YAChD,IAAI,eAAe,CAAC,IAAI,GAAG,CAAC,EAAE;gBAC7B,SAAS,CAAC,cAAc,EAAE,CAAC;gBAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,IAAI,eAAe,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;oBACvE,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;oBACvC,IAAI,CAAC,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,CAAA,EAAE;wBAC1B,SAAS;qBACT;oBACD,SAAS,CAAC,kBAAkB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;oBAClD,IAAI,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;wBAChD,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;qBAC5C;iBACD;gBACD,SAAS,CAAC,aAAa,EAAE,CAAC;aAC1B;SACD;QAED,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,gBAAgB,CAAC,cAAc,GAAG,SAAS,CAAC,mBAAmB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAGvF,gBAAgB,CAAC,UAAU,GAAG,EAAE,CAAC;QACjC,gBAAgB,CAAC,WAAW,GAAG,EAAE,CAAC;QAElC,OAAO,gBAAgB,CAAC;KACxB;YAAS;QACT,IAAI,WAAW,CAAC,UAAU,EAAE;YAC3B,wBAAU,CAAC,MAAM,GAAG,KAAK,CAAC;SAC1B;KACD;AACF,CAAC,CAAC;AA7MW,QAAA,cAAc,kBA6MzB;AAEF,MAAM,sBAAsB,GAAG,CAAC,gBAAkC,EAAE,KAAoB,EAAE,gBAAwB,EAAE,EAAE;IACrH,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,GAAG,gBAAgB,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IAC1F,gBAAgB,CAAC,UAAU,GAAG,aAAa,CAC1C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACnE,gBAAgB,CAAC,GAAG,EACpB,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,gBAAgB,GAAG,aAAa,CAChD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACzE,gBAAgB,CAAC,SAAS,EAC1B,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,WAAW,GAAG,aAAa,CAC3C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EACpE,gBAAgB,CAAC,IAAI,EACrB,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,iBAAiB,GAAG,aAAa,CACjD,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,EAC1E,gBAAgB,CAAC,UAAU,EAC3B,YAAY,CACZ,CAAC;IACF,gBAAgB,CAAC,WAAW,GAAG,aAAa,CAC3C,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,gBAAgB,CAAC,WAAW,GAAG,gBAAgB,CAAC,UAAU,CAAC,EAC7E,gBAAgB,CAAC,IAAI,EACrB,YAAY,CACZ,CAAC;IAIF,MAAM,cAAc,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,eAAe,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,MAAM,cAAc,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAC3F,MAAM,eAAe,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAC7F,gBAAgB,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,gBAAgB,CAAC,iBAAiB,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzG,gBAAgB,CAAC,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,gBAAgB,CAAC,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;IAElF,IACC,gBAAgB,CAAC,gBAAgB,GAAG,CAAC;QACrC,gBAAgB,CAAC,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,EACtE;QACD,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;KACzC;IACD,IACC,gBAAgB,CAAC,iBAAiB,GAAG,CAAC;QACtC,gBAAgB,CAAC,iBAAiB,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,EACzE;QACD,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;KAC1C;AACF,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,WAAqB,EAAE,gBAAwB,EAAgC,EAAE;IAC9G,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;KAC1B;IAGD,MAAM,YAAY,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAG5D,MAAM,UAAU,GAAG,CAAC,GAAa,EAAE,CAAS,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAE7D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,YAAoB,EAAE,YAAoB,EAAE,UAAkB,EAAU,EAAE;IAChG,IAAI,YAAY,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE;QAC7C,OAAO,IAAI,CAAC;KACZ;IACD,IAAI,YAAY,KAAK,GAAG,IAAI,YAAY,KAAK,UAAU,EAAE;QACxD,OAAO,IAAI,CAAC;KACZ;IACD,OAAO,YAAY,CAAC;AACrB,CAAC,CAAC","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 { 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\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\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\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\r\n\t// Apply debug state from input when present (e.g. from bug report)\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = true;\r\n\t\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\t\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\r\n\t\t\tattacker: { ...f.attacker },\r\n\t\t\tdefender: { ...f.defender },\r\n\t\t}));\r\n\t\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\t\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\t\tsource: { ...p.source },\r\n\t\t\ttarget: { ...p.target },\r\n\t\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t\t}));\r\n\t}\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 runSingleBattle = () => {\r\n\t\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\t\tlet playerInitialState = null;\r\n\t\tlet opponentInitialState = null;\r\n\t\tconst buildInitialStates = () => {\r\n\t\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\t\tplayerInitialState = {\r\n\t\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t\t};\r\n\t\t\topponentInitialState = {\r\n\t\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t\t};\r\n\t\t};\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\tget playerInitial() {\r\n\t\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn playerInitialState;\r\n\t\t\t\t},\r\n\t\t\t\tget opponentInitial() {\r\n\t\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn opponentInitialState;\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\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n\t};\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 = runSingleBattle();\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 = runSingleBattle();\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\tif (battleInput.debugState) {\r\n\t\t\tdebugState.active = false;\r\n\t\t}\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"]}
|
|
@@ -143,13 +143,13 @@ const handleAddedMinionAuraEffect = (board, boardHero, otherBoard, otherHero, sp
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
+
if (applySelfAuras) {
|
|
147
|
+
(0, exports.applyAurasToSelf)(spawned, board, boardHero, gameState);
|
|
148
|
+
}
|
|
146
149
|
const cardIds = [spawned.cardId, ...((_f = spawned.additionalCards) !== null && _f !== void 0 ? _f : [])];
|
|
147
150
|
for (const spawnedCardId of cardIds) {
|
|
148
151
|
handleMinionAddedAuraEffect(spawnedCardId, spawned, board, boardHero, gameState, isActuallySpawned);
|
|
149
152
|
}
|
|
150
|
-
if (applySelfAuras) {
|
|
151
|
-
(0, exports.applyAurasToSelf)(spawned, board, boardHero, gameState);
|
|
152
|
-
}
|
|
153
153
|
if (isActuallySpawned) {
|
|
154
154
|
if ((0, utils_2.hasCorrectTribe)(spawned, boardHero, reference_data_1.Race.BEAST, gameState.anomalies, gameState.allCards)) {
|
|
155
155
|
boardHero.globalInfo.BeastsSummonedThisCombat++;
|