@firestone-hs/bgs-global-stats 1.0.42 → 1.0.43

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.
@@ -35,7 +35,7 @@ const mergeStatsForSingleHero = (stats, allCards) => {
35
35
  placementDistribution: mergePlacementDistributions(stats),
36
36
  warbandStats: mergeWarbandStats(stats),
37
37
  combatWinrate: mergeCombatWinrate(stats, debug),
38
- tribeStats: mergeTribeStats(stats, averagePosition),
38
+ tribeStats: mergeTribeStats(stats, averagePosition).filter((s) => s.dataPointsOnMissingTribe > s.dataPoints / 20),
39
39
  anomalyStats: [],
40
40
  };
41
41
  return result;
@@ -48,11 +48,10 @@ const mergeTribeStats = (stats, refAveragePosition) => {
48
48
  const totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);
49
49
  const averagePosition = tribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /
50
50
  totalStatDataPoints;
51
- const impactAveragePosition = tribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /
52
- totalStatDataPoints;
53
- const impactAveragePositionVsMissingTribe = tribeStats
54
- .map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)
55
- .reduce((a, b) => a + b, 0) / totalStatDataPoints;
51
+ const averagePositionWithoutTribe = tribeStats
52
+ .map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)
53
+ .reduce((a, b) => a + b, 0) /
54
+ tribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);
56
55
  return {
57
56
  tribe: tribe,
58
57
  dataPoints: totalStatDataPoints,
@@ -60,9 +59,10 @@ const mergeTribeStats = (stats, refAveragePosition) => {
60
59
  .map((stat) => stat.dataPointsOnMissingTribe)
61
60
  .reduce((a, b) => a + b, 0),
62
61
  averagePosition: (0, util_functions_1.round)(averagePosition),
62
+ averagePositionWithoutTribe: (0, util_functions_1.round)(averagePositionWithoutTribe),
63
+ refAveragePosition: refAveragePosition,
63
64
  impactAveragePosition: (0, util_functions_1.round)(averagePosition - refAveragePosition),
64
- impactAveragePositionDebug: (0, util_functions_1.round)(impactAveragePosition),
65
- impactAveragePositionVsMissingTribe: (0, util_functions_1.round)(impactAveragePositionVsMissingTribe),
65
+ impactAveragePositionVsMissingTribe: (0, util_functions_1.round)(averagePositionWithoutTribe - refAveragePosition),
66
66
  };
67
67
  });
68
68
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\treturn result;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst impactAveragePosition =\r\n\t\t\ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst impactAveragePositionVsMissingTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) / totalStatDataPoints;\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: totalStatDataPoints,\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\timpactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(impactAveragePositionVsMissingTribe),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
1
+ {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":";;;AAAA,qEAAiE;AAEjE,mEAAuD;AAGhD,MAAM,UAAU,GAAG,CACzB,UAAqC,EACrC,aAAkC,EAClC,QAAyB,EACM,EAAE;IACjC,MAAM,QAAQ,GAAiC,UAAU;SACvD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,KAAK,aAAa,CAAC;SACtD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,2BAA8B,CAAC,CAAC;IAElE,MAAM,aAAa,GAEf,IAAA,kCAAe,EAAC,CAAC,IAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAiC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACvF,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,CACxC,CAAC;IACF,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAjBW,QAAA,UAAU,cAiBrB;AAEF,MAAM,uBAAuB,GAAG,CAAC,KAAmC,EAAE,QAAyB,EAAqB,EAAE;IACrH,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,KAAK,eAAe,CAAC;IAEjD,MAAM,oBAAoB,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3G,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAClF,MAAM,eAAe,GAAG,oBAAoB,GAAG,eAAe,CAAC;IAE/D,MAAM,qBAAqB,GAAG,KAAK;SACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,UAAU,CAAC;SACpE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7B,MAAM,eAAe,GAAG,qBAAqB,GAAG,eAAe,CAAC;IAChE,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,0BAA0B,GAAG,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAElF,MAAM,MAAM,GAAsB;QACjC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,eAAe,EAAE,IAAA,sBAAK,EAAC,eAAe,CAAC;QACvC,iBAAiB,EAAE,IAAA,sBAAK,EAAC,iBAAiB,CAAC;QAC3C,0BAA0B,EAAE,IAAA,sBAAK,EAAC,0BAA0B,CAAC;QAC7D,4BAA4B,EAAE,IAAA,sBAAK,EAAC,eAAe,GAAG,CAAC,GAAG,0BAA0B,CAAC;QACrF,qBAAqB,EAAE,2BAA2B,CAAC,KAAK,CAAC;QACzD,YAAY,EAAE,iBAAiB,CAAC,KAAK,CAAC;QACtC,aAAa,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC;QAC/C,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,MAAM,CACzD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB,GAAG,CAAC,CAAC,UAAU,GAAG,EAAE,CACrD;QACD,YAAY,EAAE,EAAE;KAChB,CAAC;IACF,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CACvB,KAAmC,EACnC,kBAA0B,EACI,EAAE;IAChC,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,MAAM,MAAM,GAAuB,CAAC,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAClE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACxE,MAAM,mBAAmB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACjG,MAAM,eAAe,GACpB,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3F,mBAAmB,CAAC;QACrB,MAAM,2BAA2B,GAChC,UAAU;aACR,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,2BAA2B,GAAG,IAAI,CAAC,wBAAwB,CAAC;aAC/E,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAQpF,OAAO;YACN,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,mBAAmB;YAC/B,wBAAwB,EAAE,UAAU;iBAClC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC;iBAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,eAAe,EAAE,IAAA,sBAAK,EAAC,eAAe,CAAC;YACvC,2BAA2B,EAAE,IAAA,sBAAK,EAAC,2BAA2B,CAAC;YAC/D,kBAAkB,EAAE,kBAAkB;YACtC,qBAAqB,EAAE,IAAA,sBAAK,EAAC,eAAe,GAAG,kBAAkB,CAAC;YAElE,mCAAmC,EAAE,IAAA,sBAAK,EAAC,2BAA2B,GAAG,kBAAkB,CAAC;SAC5F,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,2BAA2B,GAAG,CACnC,KAAmC,EACe,EAAE;;IACpD,MAAM,QAAQ,GAAG,8BAA8B,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,MAAM,GAA2C,EAAE,CAAC;IAC1D,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAW,MAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,0CAAE,YAAY,mCAAI,CAAC,CAAC;QAC5E,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,IAAA,sBAAK,EAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;KAC7E;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,8BAA8B,GAAG,CACtC,KAAmC,EACiB,EAAE;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAkBpE,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAW,QAAQ;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,eAAC,OAAA,MAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,0CAAE,YAAY,mCAAI,CAAC,CAAA,EAAA,CAAC;aACjE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;KAC9C;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,KAAmC,EAAqD,EAAE;IACpH,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,IAAA,sBAAK,EAAC,YAAY,CAAC,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;KACjG;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC5B,KAAmC,EACkE,EAAE;IACvG,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,MAAM,CAAA,CAAC,CAAC;IACtF,MAAM,MAAM,GAA+D,EAAE,CAAC;IAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACrF,MAAM,UAAU,GAAW,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,UAAU,mCAAI,CAAC,CAAA,EAAA,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACrG,MAAM,eAAe,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,UAAU,mCAAI,CAAC,CAAA,EAAA,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,CAAC;KAC9E;IACD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAC1B,KAAmC,EACnC,KAAK,GAAG,KAAK,EACkC,EAAE;IACjD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAClE,MAAM,MAAM,GAAwC,EAAE,CAAC;IACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAA,sBAAK,EAAC,WAAW,CAAC,YAAY,GAAG,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;KAC5F;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAC7B,KAAmC,EACnC,KAAK,GAAG,KAAK,EAC0F,EAAE;IACzG,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,CAAA,CAAC,CAAC;IAE7F,MAAM,MAAM,GAAiE,EAAE,CAAC;IAChF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACrF,MAAM,YAAY,GAAW,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,YAAY,mCAAI,CAAC,CAAA,EAAA,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACzG,MAAM,eAAe,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,UAAU,mCAAI,CAAC,CAAA,EAAA,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,CAAC;KAClF;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,QAAqC,EAAU,EAAE;IACpE,IAAI,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,MAAM,CAAA,EAAE;QACtB,OAAO,CAAC,CAAC;KACT;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC,CAAC","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\treturn result;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition).filter(\r\n\t\t\t(s) => s.dataPointsOnMissingTribe > s.dataPoints / 20,\r\n\t\t),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst averagePositionWithoutTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePosition =\r\n\t\t// \ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t// \ttotalStatDataPoints;\r\n\t\t// const impactAveragePositionVsMissingTribe =\r\n\t\t// \ttribeStats\r\n\t\t// \t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t// \t\t.reduce((a, b) => a + b, 0) / totalStatDataPoints;\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: totalStatDataPoints,\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\taveragePositionWithoutTribe: round(averagePositionWithoutTribe),\r\n\t\t\trefAveragePosition: refAveragePosition,\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\t// impactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(averagePositionWithoutTribe - refAveragePosition),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
@@ -51,6 +51,7 @@ const buildTribeStats = (rows, refAveragePosition) => {
51
51
  dataPoints: rowsForTribe.length,
52
52
  dataPointsOnMissingTribe: rowsWithoutTribe.length,
53
53
  averagePosition: averagePosition,
54
+ averagePositionWithoutTribe: averagePositionWithoutTribe,
54
55
  impactAveragePosition: averagePosition - refAveragePosition,
55
56
  impactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,
56
57
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/duos/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.rank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.rank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.rank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \t});\r\n// };\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
1
+ {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/duos/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.rank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.rank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.rank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\taveragePositionWithoutTribe: averagePositionWithoutTribe,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \t});\r\n// };\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
package/dist/models.d.ts CHANGED
@@ -46,6 +46,7 @@ export interface BgsHeroTribeStat {
46
46
  readonly dataPoints: number;
47
47
  readonly dataPointsOnMissingTribe: number;
48
48
  readonly averagePosition: number;
49
+ readonly averagePositionWithoutTribe: number;
49
50
  readonly impactAveragePosition: number;
50
51
  readonly impactAveragePositionVsMissingTribe: number;
51
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly standardDeviation: number;\r\n\treadonly standardDeviationOfTheMean: number;\r\n\treadonly conservativePositionEstimate: number;\r\n\treadonly placementDistribution?: readonly { rank: number; percentage: number }[];\r\n\treadonly placementDistributionRaw?: readonly { rank: number; totalMatches: number }[];\r\n\treadonly combatWinrate?: readonly { turn: number; winrate: number }[];\r\n\treadonly combatWinrateRaw?: readonly { turn: number; dataPoints: number; totalWinrate: number }[];\r\n\treadonly warbandStats?: readonly { turn: number; averageStats: number }[];\r\n\treadonly warbandStatsRaw?: readonly { turn: number; dataPoints: number; totalStats: number }[];\r\n\treadonly tribeStats: readonly BgsHeroTribeStat[];\r\n\treadonly anomalyStats: readonly BgsHeroAnomalyStat[];\r\n}\r\n\r\nexport interface BgsHeroTribeStat {\r\n\treadonly tribe: Race;\r\n\treadonly dataPoints: number;\r\n\treadonly dataPointsOnMissingTribe: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly impactAveragePositionVsMissingTribe: number;\r\n\t// readonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\t// readonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\t// readonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\t// readonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n\t// readonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\t// readonly impactWarbandStats: readonly { turn: number; impact: number }[];\r\n}\r\n\r\nexport interface BgsHeroAnomalyStat {\r\n\treadonly anomaly: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly placementDistributionRaw: readonly { rank: number; totalMatches: number }[];\r\n\treadonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n\treadonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\treadonly impactWarbandStats: readonly { turn: number; impact: number }[];\r\n}\r\n\r\nexport type WithMmrAndTimePeriod<T> = T & {\r\n\treadonly mmrPercentile: MmrPercentileFilter;\r\n\treadonly timePeriod: TimePeriod;\r\n};\r\n\r\nexport interface MmrPercentile {\r\n\treadonly mmr: number;\r\n\treadonly percentile: MmrPercentileFilter;\r\n}\r\n\r\nexport type TimePeriod = 'all-time' | 'past-three' | 'past-seven' | 'last-patch';\r\nexport type MmrPercentileFilter = 100 | 50 | 25 | 10 | 1;\r\n"]}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly standardDeviation: number;\r\n\treadonly standardDeviationOfTheMean: number;\r\n\treadonly conservativePositionEstimate: number;\r\n\treadonly placementDistribution?: readonly { rank: number; percentage: number }[];\r\n\treadonly placementDistributionRaw?: readonly { rank: number; totalMatches: number }[];\r\n\treadonly combatWinrate?: readonly { turn: number; winrate: number }[];\r\n\treadonly combatWinrateRaw?: readonly { turn: number; dataPoints: number; totalWinrate: number }[];\r\n\treadonly warbandStats?: readonly { turn: number; averageStats: number }[];\r\n\treadonly warbandStatsRaw?: readonly { turn: number; dataPoints: number; totalStats: number }[];\r\n\treadonly tribeStats: readonly BgsHeroTribeStat[];\r\n\treadonly anomalyStats: readonly BgsHeroAnomalyStat[];\r\n}\r\n\r\nexport interface BgsHeroTribeStat {\r\n\treadonly tribe: Race;\r\n\treadonly dataPoints: number;\r\n\treadonly dataPointsOnMissingTribe: number;\r\n\treadonly averagePosition: number;\r\n\treadonly averagePositionWithoutTribe: number;\r\n\t// Impacts are only meant to be used in the final output\r\n\treadonly impactAveragePosition: number;\r\n\treadonly impactAveragePositionVsMissingTribe: number;\r\n\t// readonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\t// readonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\t// readonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\t// readonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n\t// readonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\t// readonly impactWarbandStats: readonly { turn: number; impact: number }[];\r\n}\r\n\r\nexport interface BgsHeroAnomalyStat {\r\n\treadonly anomaly: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly placementDistributionRaw: readonly { rank: number; totalMatches: number }[];\r\n\treadonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n\treadonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\treadonly impactWarbandStats: readonly { turn: number; impact: number }[];\r\n}\r\n\r\nexport type WithMmrAndTimePeriod<T> = T & {\r\n\treadonly mmrPercentile: MmrPercentileFilter;\r\n\treadonly timePeriod: TimePeriod;\r\n};\r\n\r\nexport interface MmrPercentile {\r\n\treadonly mmr: number;\r\n\treadonly percentile: MmrPercentileFilter;\r\n}\r\n\r\nexport type TimePeriod = 'all-time' | 'past-three' | 'past-seven' | 'last-patch';\r\nexport type MmrPercentileFilter = 100 | 50 | 25 | 10 | 1;\r\n"]}
@@ -35,7 +35,7 @@ const mergeStatsForSingleHero = (stats, allCards) => {
35
35
  placementDistribution: mergePlacementDistributions(stats),
36
36
  warbandStats: mergeWarbandStats(stats),
37
37
  combatWinrate: mergeCombatWinrate(stats, debug),
38
- tribeStats: mergeTribeStats(stats, averagePosition),
38
+ tribeStats: mergeTribeStats(stats, averagePosition).filter((s) => s.dataPointsOnMissingTribe > s.dataPoints / 20),
39
39
  anomalyStats: [],
40
40
  };
41
41
  return result;
@@ -47,11 +47,10 @@ const mergeTribeStats = (stats, refAveragePosition) => {
47
47
  const tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);
48
48
  const averagePosition = tribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /
49
49
  tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);
50
- const impactAveragePosition = tribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /
51
- tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);
52
- const impactAveragePositionVsMissingTribe = tribeStats
53
- .map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)
54
- .reduce((a, b) => a + b, 0) / tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);
50
+ const averagePositionWithoutTribe = tribeStats
51
+ .map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)
52
+ .reduce((a, b) => a + b, 0) /
53
+ tribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);
55
54
  return {
56
55
  tribe: tribe,
57
56
  dataPoints: tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),
@@ -59,9 +58,10 @@ const mergeTribeStats = (stats, refAveragePosition) => {
59
58
  .map((stat) => stat.dataPointsOnMissingTribe)
60
59
  .reduce((a, b) => a + b, 0),
61
60
  averagePosition: (0, util_functions_1.round)(averagePosition),
61
+ averagePositionWithoutTribe: (0, util_functions_1.round)(averagePositionWithoutTribe),
62
+ refAveragePosition: (0, util_functions_1.round)(refAveragePosition),
62
63
  impactAveragePosition: (0, util_functions_1.round)(averagePosition - refAveragePosition),
63
- impactAveragePositionDebug: (0, util_functions_1.round)(impactAveragePosition),
64
- impactAveragePositionVsMissingTribe: (0, util_functions_1.round)(impactAveragePositionVsMissingTribe),
64
+ impactAveragePositionVsMissingTribe: (0, util_functions_1.round)(averagePositionWithoutTribe - refAveragePosition),
65
65
  };
66
66
  });
67
67
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/solo/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\treturn result;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst impactAveragePosition =\r\n\t\t\ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst impactAveragePositionVsMissingTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) / tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\timpactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(impactAveragePositionVsMissingTribe),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
1
+ {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/solo/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\treturn result;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition).filter(\r\n\t\t\t(s) => s.dataPointsOnMissingTribe > s.dataPoints / 20,\r\n\t\t),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePositionWithoutTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePosition =\r\n\t\t// \ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t// \ttribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePositionVsMissingTribe =\r\n\t\t// \ttribeStats\r\n\t\t// \t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t// \t\t.reduce((a, b) => a + b, 0) / tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\taveragePositionWithoutTribe: round(averagePositionWithoutTribe),\r\n\t\t\trefAveragePosition: round(refAveragePosition),\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\t// impactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(averagePositionWithoutTribe - refAveragePosition),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
@@ -51,6 +51,7 @@ const buildTribeStats = (rows, refAveragePosition) => {
51
51
  dataPoints: rowsForTribe.length,
52
52
  dataPointsOnMissingTribe: rowsWithoutTribe.length,
53
53
  averagePosition: averagePosition,
54
+ averagePositionWithoutTribe: averagePositionWithoutTribe,
54
55
  impactAveragePosition: averagePosition - refAveragePosition,
55
56
  impactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,
56
57
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/solo/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.rank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.rank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.rank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \t});\r\n// };\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
1
+ {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/solo/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.rank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.rank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.rank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\taveragePositionWithoutTribe: averagePositionWithoutTribe,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \t});\r\n// };\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestone-hs/bgs-global-stats",
3
- "version": "1.0.42",
3
+ "version": "1.0.43",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "lint": "eslint --color --fix --ext .ts .",