@idealic/poker-engine
Version:
Poker game engine and hand evaluator
1,044 lines (912 loc) • 43.7 kB
text/typescript
import { emptyStatValues } from './stats';
import { PokerMetrics, StreetStat } from './types';
export const emptyMetric: Omit<
PokerMetrics,
'hand' | 'table' | 'player' | 'createdAt' | 'street' | 'venue' | 'isFinalAction'
> = {
...emptyStatValues,
startedAt: Date.now(),
gameIds: new Set(['12345']),
distinctGameCount: 0,
limpFrequency: 0,
aggressionFactor: 0,
aggressionFrequency: 0,
vpipFrequency: 0,
allInFrequency: 0,
sawFlopFrequency: 0,
potAverage: 0,
// IP/OOP Aggressor Frequencies
threeBetIpFrequency: 0,
threeBetOopFrequency: 0,
threeBetIpTakedownFrequency: 0,
threeBetOopTakedownFrequency: 0,
fourBetIpFrequency: 0,
fourBetOopFrequency: 0,
fourBetIpTakedownFrequency: 0,
fourBetOopTakedownFrequency: 0,
fiveBetIpFrequency: 0,
fiveBetOopFrequency: 0,
fiveBetIpTakedownFrequency: 0,
fiveBetOopTakedownFrequency: 0,
cbetIpFrequency: 0,
cbetOopFrequency: 0,
cbetIpTakedownFrequency: 0,
cbetOopTakedownFrequency: 0,
stealIpFrequency: 0,
stealOopFrequency: 0,
stealIpTakedownFrequency: 0,
stealOopTakedownFrequency: 0,
donkBetFrequency: 0,
donkBetTakedownFrequency: 0,
checkRaiseFrequency: 0,
checkRaiseTakedownFrequency: 0,
openShoveIpFrequency: 0,
openShoveOopFrequency: 0,
openShoveIpTakedownFrequency: 0,
openShoveOopTakedownFrequency: 0,
// Squeeze IP/OOP Aggressor Frequencies
squeezeIpFrequency: 0,
squeezeOopFrequency: 0,
squeezeIpTakedownFrequency: 0,
squeezeOopTakedownFrequency: 0,
// Delayed C-Bet IP/OOP Aggressor Frequencies
delayedCbetIpFrequency: 0,
delayedCbetOopFrequency: 0,
delayedCbetIpTakedownFrequency: 0,
delayedCbetOopTakedownFrequency: 0,
// Double Barrel IP/OOP Aggressor Frequencies
doubleBarrelIpFrequency: 0,
doubleBarrelOopFrequency: 0,
doubleBarrelIpTakedownFrequency: 0,
doubleBarrelOopTakedownFrequency: 0,
// Triple Barrel IP/OOP Aggressor Frequencies
tripleBarrelIpFrequency: 0,
tripleBarrelOopFrequency: 0,
tripleBarrelIpTakedownFrequency: 0,
tripleBarrelOopTakedownFrequency: 0,
// Shove IP/OOP Aggressor Frequencies
shoveIpFrequency: 0,
shoveOopFrequency: 0,
shoveIpTakedownFrequency: 0,
shoveOopTakedownFrequency: 0,
// IP/OOP Defender Frequencies
threeBetIpFoldFrequency: 0,
threeBetOopFoldFrequency: 0,
threeBetIpContinueFrequency: 0,
threeBetOopContinueFrequency: 0,
fourBetIpFoldFrequency: 0,
fourBetOopFoldFrequency: 0,
fourBetIpContinueFrequency: 0,
fourBetOopContinueFrequency: 0,
fiveBetIpFoldFrequency: 0,
fiveBetOopFoldFrequency: 0,
fiveBetIpContinueFrequency: 0,
fiveBetOopContinueFrequency: 0,
cbetIpFoldFrequency: 0,
cbetOopFoldFrequency: 0,
cbetIpContinueFrequency: 0,
cbetOopContinueFrequency: 0,
stealIpFoldFrequency: 0,
stealOopFoldFrequency: 0,
stealIpContinueFrequency: 0,
stealOopContinueFrequency: 0,
donkBetFoldFrequency: 0,
donkBetContinueFrequency: 0,
checkRaiseFoldFrequency: 0,
checkRaiseContinueFrequency: 0,
openShoveIpFoldFrequency: 0,
openShoveOopFoldFrequency: 0,
openShoveIpContinueFrequency: 0,
openShoveOopContinueFrequency: 0,
// Squeeze IP/OOP Defender Frequencies
squeezeIpFoldFrequency: 0,
squeezeOopFoldFrequency: 0,
squeezeIpContinueFrequency: 0,
squeezeOopContinueFrequency: 0,
// Delayed C-Bet IP/OOP Defender Frequencies
delayedCbetIpFoldFrequency: 0,
delayedCbetOopFoldFrequency: 0,
delayedCbetIpContinueFrequency: 0,
delayedCbetOopContinueFrequency: 0,
// Double Barrel IP/OOP Defender Frequencies
doubleBarrelIpFoldFrequency: 0,
doubleBarrelOopFoldFrequency: 0,
doubleBarrelIpContinueFrequency: 0,
doubleBarrelOopContinueFrequency: 0,
// Triple Barrel IP/OOP Defender Frequencies
tripleBarrelIpFoldFrequency: 0,
tripleBarrelOopFoldFrequency: 0,
tripleBarrelIpContinueFrequency: 0,
tripleBarrelOopContinueFrequency: 0,
// Shove IP/OOP Defender Frequencies
shoveIpFoldFrequency: 0,
shoveOopFoldFrequency: 0,
shoveIpContinueFrequency: 0,
shoveOopContinueFrequency: 0,
// PFR
preflopRaiseOpportunities: 0,
preflopRaises: 0,
preflopRaiseFrequency: 0,
// --- Maneuver-Specific Metrics ---
threeBetOpportunities: 0,
threeBetAttempts: 0,
threeBetChallenges: 0,
threeBetContinues: 0,
threeBetFolds: 0,
threeBetTakedowns: 0,
threeBetFrequency: 0,
threeBetFoldFrequency: 0,
threeBetContinueFrequency: 0,
threeBetTakedownFrequency: 0,
squeezeOpportunities: 0,
squeezeAttempts: 0,
squeezeChallenges: 0,
squeezeContinues: 0,
squeezeFolds: 0,
squeezeTakedowns: 0,
squeezeFrequency: 0,
squeezeFoldFrequency: 0,
squeezeContinueFrequency: 0,
squeezeTakedownFrequency: 0,
fourBetOpportunities: 0,
fourBetAttempts: 0,
fourBetChallenges: 0,
fourBetContinues: 0,
fourBetFolds: 0,
fourBetTakedowns: 0,
fourBetFrequency: 0,
fourBetFoldFrequency: 0,
fourBetContinueFrequency: 0,
fourBetTakedownFrequency: 0,
fiveBetOpportunities: 0,
fiveBetAttempts: 0,
fiveBetChallenges: 0,
fiveBetContinues: 0,
fiveBetFolds: 0,
fiveBetTakedowns: 0,
fiveBetFrequency: 0,
fiveBetFoldFrequency: 0,
fiveBetContinueFrequency: 0,
fiveBetTakedownFrequency: 0,
cbetOpportunities: 0,
cbetAttempts: 0,
cbetChallenges: 0,
cbetContinues: 0,
cbetFolds: 0,
cbetTakedowns: 0,
cbetFrequency: 0,
cbetFoldFrequency: 0,
cbetContinueFrequency: 0,
cbetTakedownFrequency: 0,
delayedCbetOpportunities: 0,
delayedCbetAttempts: 0,
delayedCbetChallenges: 0,
delayedCbetContinues: 0,
delayedCbetFolds: 0,
delayedCbetTakedowns: 0,
delayedCbetFrequency: 0,
delayedCbetFoldFrequency: 0,
delayedCbetContinueFrequency: 0,
delayedCbetTakedownFrequency: 0,
doubleBarrelOpportunities: 0,
doubleBarrelAttempts: 0,
doubleBarrelChallenges: 0,
doubleBarrelContinues: 0,
doubleBarrelFolds: 0,
doubleBarrelTakedowns: 0,
doubleBarrelFrequency: 0,
doubleBarrelFoldFrequency: 0,
doubleBarrelContinueFrequency: 0,
doubleBarrelTakedownFrequency: 0,
tripleBarrelOpportunities: 0,
tripleBarrelAttempts: 0,
tripleBarrelChallenges: 0,
tripleBarrelContinues: 0,
tripleBarrelFolds: 0,
tripleBarrelTakedowns: 0,
tripleBarrelFrequency: 0,
tripleBarrelFoldFrequency: 0,
tripleBarrelContinueFrequency: 0,
tripleBarrelTakedownFrequency: 0,
probeBetFrequency: 0,
probeBetFoldFrequency: 0,
probeBetContinueFrequency: 0,
probeBetTakedownFrequency: 0,
floatBetFrequency: 0,
floatBetFoldFrequency: 0,
floatBetContinueFrequency: 0,
floatBetTakedownFrequency: 0,
stealOpportunities: 0,
stealAttempts: 0,
stealChallenges: 0,
stealContinues: 0,
stealFolds: 0,
stealTakedowns: 0,
stealFrequency: 0,
stealFoldFrequency: 0,
stealContinueFrequency: 0,
stealTakedownFrequency: 0,
openShoveOpportunities: 0,
openShoveAttempts: 0,
openShoveChallenges: 0,
openShoveContinues: 0,
openShoveFolds: 0,
openShoveTakedowns: 0,
openShoveFrequency: 0,
openShoveFoldFrequency: 0,
openShoveContinueFrequency: 0,
openShoveTakedownFrequency: 0,
shoveOpportunities: 0,
shoveAttempts: 0,
shoveChallenges: 0,
shoveContinues: 0,
shoveFolds: 0,
shoveTakedowns: 0,
shoveFrequency: 0,
shoveFoldFrequency: 0,
shoveContinueFrequency: 0,
shoveTakedownFrequency: 0,
// IP/OOP Aggressor Metrics
threeBetIpAttempts: 0,
threeBetIpOpportunities: 0,
threeBetIpTakedowns: 0,
threeBetOopAttempts: 0,
threeBetOopOpportunities: 0,
threeBetOopTakedowns: 0,
fourBetIpAttempts: 0,
fourBetIpOpportunities: 0,
fourBetIpTakedowns: 0,
fourBetOopAttempts: 0,
fourBetOopOpportunities: 0,
fourBetOopTakedowns: 0,
fiveBetIpAttempts: 0,
fiveBetIpOpportunities: 0,
fiveBetIpTakedowns: 0,
fiveBetOopAttempts: 0,
fiveBetOopOpportunities: 0,
fiveBetOopTakedowns: 0,
cbetIpAttempts: 0,
cbetIpOpportunities: 0,
cbetIpTakedowns: 0,
cbetOopAttempts: 0,
cbetOopOpportunities: 0,
cbetOopTakedowns: 0,
stealIpAttempts: 0,
stealIpOpportunities: 0,
stealIpTakedowns: 0,
stealOopAttempts: 0,
stealOopOpportunities: 0,
stealOopTakedowns: 0,
donkBetAttempts: 0,
donkBetOpportunities: 0,
donkBetTakedowns: 0,
donkBetFolds: 0,
donkBetContinues: 0,
donkBetChallenges: 0,
checkRaiseAttempts: 0,
checkRaiseOpportunities: 0,
checkRaiseTakedowns: 0,
checkRaiseFolds: 0,
checkRaiseContinues: 0,
checkRaiseChallenges: 0,
openShoveIpAttempts: 0,
openShoveIpOpportunities: 0,
openShoveIpTakedowns: 0,
openShoveOopAttempts: 0,
openShoveOopOpportunities: 0,
openShoveOopTakedowns: 0,
// Squeeze IP/OOP Aggressor Metrics
squeezeIpAttempts: 0,
squeezeIpOpportunities: 0,
squeezeIpTakedowns: 0,
squeezeOopAttempts: 0,
squeezeOopOpportunities: 0,
squeezeOopTakedowns: 0,
// Delayed C-Bet IP/OOP Aggressor Metrics
delayedCbetIpAttempts: 0,
delayedCbetIpOpportunities: 0,
delayedCbetIpTakedowns: 0,
delayedCbetOopAttempts: 0,
delayedCbetOopOpportunities: 0,
delayedCbetOopTakedowns: 0,
// Double Barrel IP/OOP Aggressor Metrics
doubleBarrelIpAttempts: 0,
doubleBarrelIpOpportunities: 0,
doubleBarrelIpTakedowns: 0,
doubleBarrelOopAttempts: 0,
doubleBarrelOopOpportunities: 0,
doubleBarrelOopTakedowns: 0,
// Triple Barrel IP/OOP Aggressor Metrics
tripleBarrelIpAttempts: 0,
tripleBarrelIpOpportunities: 0,
tripleBarrelIpTakedowns: 0,
tripleBarrelOopAttempts: 0,
tripleBarrelOopOpportunities: 0,
tripleBarrelOopTakedowns: 0,
// Shove IP/OOP Aggressor Metrics
shoveIpAttempts: 0,
shoveIpOpportunities: 0,
shoveIpTakedowns: 0,
shoveOopAttempts: 0,
shoveOopOpportunities: 0,
shoveOopTakedowns: 0,
// IP/OOP Defender Metrics
threeBetIpChallenges: 0,
threeBetIpContinues: 0,
threeBetIpFolds: 0,
threeBetOopChallenges: 0,
threeBetOopContinues: 0,
threeBetOopFolds: 0,
fourBetIpChallenges: 0,
fourBetIpContinues: 0,
fourBetIpFolds: 0,
fourBetOopChallenges: 0,
fourBetOopContinues: 0,
fourBetOopFolds: 0,
fiveBetIpChallenges: 0,
fiveBetIpContinues: 0,
fiveBetIpFolds: 0,
fiveBetOopChallenges: 0,
fiveBetOopContinues: 0,
fiveBetOopFolds: 0,
cbetIpChallenges: 0,
cbetIpContinues: 0,
cbetIpFolds: 0,
cbetOopChallenges: 0,
cbetOopContinues: 0,
cbetOopFolds: 0,
stealIpChallenges: 0,
stealIpContinues: 0,
stealIpFolds: 0,
stealOopChallenges: 0,
stealOopContinues: 0,
stealOopFolds: 0,
openShoveIpChallenges: 0,
openShoveIpContinues: 0,
openShoveIpFolds: 0,
openShoveOopChallenges: 0,
openShoveOopContinues: 0,
openShoveOopFolds: 0,
wentToShowdownFrequency: 0,
wonAtShowdownFrequency: 0,
wonWithoutShowdownFrequency: 0,
winningsAverage: 0,
investmentsAverage: 0,
profitAverage: 0,
lossesAverage: 0,
bb100: 0,
returnOnInvestmentFactor: 0,
stackToPotFactor: 0,
decisionDurationAverage: 0,
profitFactor: 0,
};
type MetricName = keyof Omit<StreetStat, 'gameIds'>;
type GroupedMetrics<T extends MetricName[]> = T extends [infer First, ...infer Rest]
? Record<
First extends MetricName ? StreetStat[First] | 'total' : string,
GroupedMetrics<Rest extends MetricName[] ? Rest : []>
>
: PokerMetrics;
export type AgregatedMetrics<T extends MetricName[]> = GroupedMetrics<T>;
function getOrCreateMetric(obj: any, key: string): PokerMetrics {
if (!obj[key]) {
obj[key] = { ...emptyMetric, gameIds: new Set() };
}
return obj[key];
}
export function getPokerMetrics<T extends (keyof StreetStat)[]>(
stats: StreetStat[],
groups: T = ['player', 'street'] as T,
withTotals = true
): AgregatedMetrics<T> & { total: PokerMetrics } {
const result: AgregatedMetrics<T> & { total: PokerMetrics } = {
total: { ...emptyMetric, gameIds: new Set() },
} as AgregatedMetrics<T> & { total: PokerMetrics };
// Process each stat
for (const stat of stats) {
let current = result;
// Process each group level
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
const value = String(stat[group]);
if (i == groups.length - 1) {
updateMetric(getOrCreateMetric(current, value), stat);
}
// Update total for current level
if (withTotals) {
updateMetric(getOrCreateMetric(current, 'total'), stat);
}
const key = value as keyof typeof current;
if (!current[key]) current[key] = {} as any;
current = current[key] as any;
}
}
// Calculate derived metrics for all levels
function updateDerivedMetrics(obj: any) {
for (const key in obj) {
const value = obj[key];
if (value && typeof value === 'object') {
if ('raises' in value) {
aggregateMetricsProperties(value);
} else {
updateDerivedMetrics(value);
}
}
}
}
updateDerivedMetrics(result);
return result;
}
export function aggregateMetricsProperties(metric: PokerMetrics): PokerMetrics {
metric.limpFrequency = metric.limps / (metric.limpOpportunities || 1);
metric.aggressionFactor = (metric.bets + metric.raises) / (metric.calls || 1);
metric.aggressionFrequency =
(metric.bets + metric.raises) /
(metric.bets + metric.raises + metric.calls + metric.folds || 1);
metric.vpipFrequency = metric.voluntaryPutMoneyInPotTimes / (metric.distinctGameCount || 1);
metric.sawFlopFrequency = (metric.sawFlop ?? 0) / (metric.distinctGameCount || 1);
metric.allInFrequency = metric.allIns / ((metric.distinctGameCount || 1) / 100);
metric.potAverage = (metric.pot ?? 0) / (metric.distinctGameCount || 1);
// --- IP/OOP Frequencies ---
// PFR
metric.preflopRaiseFrequency = metric.preflopRaises / (metric.preflopRaiseOpportunities || 1);
// 3-Bet
metric.threeBetIpFrequency = metric.threeBetIpAttempts / (metric.threeBetIpOpportunities || 1);
metric.threeBetOopFrequency = metric.threeBetOopAttempts / (metric.threeBetOopOpportunities || 1);
metric.threeBetIpTakedownFrequency =
metric.threeBetIpTakedowns / (metric.threeBetIpAttempts || 1);
metric.threeBetOopTakedownFrequency =
metric.threeBetOopTakedowns / (metric.threeBetOopAttempts || 1);
metric.threeBetIpFoldFrequency = metric.threeBetIpFolds / (metric.threeBetIpChallenges || 1);
metric.threeBetOopFoldFrequency = metric.threeBetOopFolds / (metric.threeBetOopChallenges || 1);
metric.threeBetIpContinueFrequency =
metric.threeBetIpContinues / (metric.threeBetIpChallenges || 1);
metric.threeBetOopContinueFrequency =
metric.threeBetOopContinues / (metric.threeBetOopChallenges || 1);
metric.threeBetFrequency = metric.threeBetAttempts / (metric.threeBetOpportunities || 1);
metric.threeBetTakedownFrequency = metric.threeBetTakedowns / (metric.threeBetAttempts || 1);
metric.threeBetFoldFrequency = metric.threeBetFolds / (metric.threeBetChallenges || 1);
metric.threeBetContinueFrequency = metric.threeBetContinues / (metric.threeBetChallenges || 1);
// 4-Bet
metric.fourBetIpFrequency = metric.fourBetIpAttempts / (metric.fourBetIpOpportunities || 1);
metric.fourBetOopFrequency = metric.fourBetOopAttempts / (metric.fourBetOopOpportunities || 1);
metric.fourBetIpTakedownFrequency = metric.fourBetIpTakedowns / (metric.fourBetIpAttempts || 1);
metric.fourBetOopTakedownFrequency =
metric.fourBetOopTakedowns / (metric.fourBetOopAttempts || 1);
metric.fourBetIpFoldFrequency = metric.fourBetIpFolds / (metric.fourBetIpChallenges || 1);
metric.fourBetOopFoldFrequency = metric.fourBetOopFolds / (metric.fourBetOopChallenges || 1);
metric.fourBetIpContinueFrequency = metric.fourBetIpContinues / (metric.fourBetIpChallenges || 1);
metric.fourBetOopContinueFrequency =
metric.fourBetOopContinues / (metric.fourBetOopChallenges || 1);
metric.fourBetFrequency = metric.fourBetAttempts / (metric.fourBetOpportunities || 1);
metric.fourBetTakedownFrequency = metric.fourBetTakedowns / (metric.fourBetAttempts || 1);
metric.fourBetFoldFrequency = metric.fourBetFolds / (metric.fourBetChallenges || 1);
metric.fourBetContinueFrequency = metric.fourBetContinues / (metric.fourBetChallenges || 1);
// 5-Bet
metric.fiveBetIpFrequency = metric.fiveBetIpAttempts / (metric.fiveBetIpOpportunities || 1);
metric.fiveBetOopFrequency = metric.fiveBetOopAttempts / (metric.fiveBetOopOpportunities || 1);
metric.fiveBetIpTakedownFrequency = metric.fiveBetIpTakedowns / (metric.fiveBetIpAttempts || 1);
metric.fiveBetOopTakedownFrequency =
metric.fiveBetOopTakedowns / (metric.fiveBetOopAttempts || 1);
metric.fiveBetIpFoldFrequency = metric.fiveBetIpFolds / (metric.fiveBetIpChallenges || 1);
metric.fiveBetOopFoldFrequency = metric.fiveBetOopFolds / (metric.fiveBetOopChallenges || 1);
metric.fiveBetIpContinueFrequency = metric.fiveBetIpContinues / (metric.fiveBetIpChallenges || 1);
metric.fiveBetOopContinueFrequency =
metric.fiveBetOopContinues / (metric.fiveBetOopChallenges || 1);
metric.fiveBetFrequency = metric.fiveBetAttempts / (metric.fiveBetOpportunities || 1);
metric.fiveBetTakedownFrequency = metric.fiveBetTakedowns / (metric.fiveBetAttempts || 1);
metric.fiveBetFoldFrequency = metric.fiveBetFolds / (metric.fiveBetChallenges || 1);
metric.fiveBetContinueFrequency = metric.fiveBetContinues / (metric.fiveBetChallenges || 1);
// C-Bet
metric.cbetIpFrequency = metric.cbetIpAttempts / (metric.cbetIpOpportunities || 1);
metric.cbetOopFrequency = metric.cbetOopAttempts / (metric.cbetOopOpportunities || 1);
metric.cbetIpTakedownFrequency = metric.cbetIpTakedowns / (metric.cbetIpAttempts || 1);
metric.cbetOopTakedownFrequency = metric.cbetOopTakedowns / (metric.cbetOopAttempts || 1);
metric.cbetIpFoldFrequency = metric.cbetIpFolds / (metric.cbetIpChallenges || 1);
metric.cbetOopFoldFrequency = metric.cbetOopFolds / (metric.cbetOopChallenges || 1);
metric.cbetIpContinueFrequency = metric.cbetIpContinues / (metric.cbetIpChallenges || 1);
metric.cbetOopContinueFrequency = metric.cbetOopContinues / (metric.cbetOopChallenges || 1);
metric.cbetFrequency = metric.cbetAttempts / (metric.cbetOpportunities || 1);
metric.cbetTakedownFrequency = metric.cbetTakedowns / (metric.cbetAttempts || 1);
metric.cbetFoldFrequency = metric.cbetFolds / (metric.cbetChallenges || 1);
metric.cbetContinueFrequency = metric.cbetContinues / (metric.cbetChallenges || 1);
// Delayed C-Bet
metric.delayedCbetIpFrequency =
metric.delayedCbetIpAttempts / (metric.delayedCbetIpOpportunities || 1);
metric.delayedCbetOopFrequency =
metric.delayedCbetOopAttempts / (metric.delayedCbetOopOpportunities || 1);
metric.delayedCbetIpTakedownFrequency =
metric.delayedCbetIpTakedowns / (metric.delayedCbetIpAttempts || 1);
metric.delayedCbetOopTakedownFrequency =
metric.delayedCbetOopTakedowns / (metric.delayedCbetOopAttempts || 1);
metric.delayedCbetIpFoldFrequency =
metric.delayedCbetIpFolds / (metric.delayedCbetIpChallenges || 1);
metric.delayedCbetOopFoldFrequency =
metric.delayedCbetOopFolds / (metric.delayedCbetOopChallenges || 1);
metric.delayedCbetIpContinueFrequency =
metric.delayedCbetIpContinues / (metric.delayedCbetIpChallenges || 1);
metric.delayedCbetOopContinueFrequency =
metric.delayedCbetOopContinues / (metric.delayedCbetOopChallenges || 1);
metric.delayedCbetFrequency = metric.delayedCbetAttempts / (metric.delayedCbetOpportunities || 1);
metric.delayedCbetTakedownFrequency =
metric.delayedCbetTakedowns / (metric.delayedCbetAttempts || 1);
metric.delayedCbetFoldFrequency = metric.delayedCbetFolds / (metric.delayedCbetChallenges || 1);
metric.delayedCbetContinueFrequency =
metric.delayedCbetContinues / (metric.delayedCbetChallenges || 1);
// Double Barrel
metric.doubleBarrelIpFrequency =
metric.doubleBarrelIpAttempts / (metric.doubleBarrelIpOpportunities || 1);
metric.doubleBarrelOopFrequency =
metric.doubleBarrelOopAttempts / (metric.doubleBarrelOopOpportunities || 1);
metric.doubleBarrelIpTakedownFrequency =
metric.doubleBarrelIpTakedowns / (metric.doubleBarrelIpAttempts || 1);
metric.doubleBarrelOopTakedownFrequency =
metric.doubleBarrelOopTakedowns / (metric.doubleBarrelOopAttempts || 1);
metric.doubleBarrelIpFoldFrequency =
metric.doubleBarrelIpFolds / (metric.doubleBarrelIpChallenges || 1);
metric.doubleBarrelOopFoldFrequency =
metric.doubleBarrelOopFolds / (metric.doubleBarrelOopChallenges || 1);
metric.doubleBarrelIpContinueFrequency =
metric.doubleBarrelIpContinues / (metric.doubleBarrelIpChallenges || 1);
metric.doubleBarrelOopContinueFrequency =
metric.doubleBarrelOopContinues / (metric.doubleBarrelOopChallenges || 1);
metric.doubleBarrelFrequency =
metric.doubleBarrelAttempts / (metric.doubleBarrelOpportunities || 1);
metric.doubleBarrelTakedownFrequency =
metric.doubleBarrelTakedowns / (metric.doubleBarrelAttempts || 1);
metric.doubleBarrelFoldFrequency =
metric.doubleBarrelFolds / (metric.doubleBarrelChallenges || 1);
metric.doubleBarrelContinueFrequency =
metric.doubleBarrelContinues / (metric.doubleBarrelChallenges || 1);
// Triple Barrel
metric.tripleBarrelIpFrequency =
metric.tripleBarrelIpAttempts / (metric.tripleBarrelIpOpportunities || 1);
metric.tripleBarrelOopFrequency =
metric.tripleBarrelOopAttempts / (metric.tripleBarrelOopOpportunities || 1);
metric.tripleBarrelIpTakedownFrequency =
metric.tripleBarrelIpTakedowns / (metric.tripleBarrelIpAttempts || 1);
metric.tripleBarrelOopTakedownFrequency =
metric.tripleBarrelOopTakedowns / (metric.tripleBarrelOopAttempts || 1);
metric.tripleBarrelIpFoldFrequency =
metric.tripleBarrelIpFolds / (metric.tripleBarrelIpChallenges || 1);
metric.tripleBarrelOopFoldFrequency =
metric.tripleBarrelOopFolds / (metric.tripleBarrelOopChallenges || 1);
metric.tripleBarrelIpContinueFrequency =
metric.tripleBarrelIpContinues / (metric.tripleBarrelIpChallenges || 1);
metric.tripleBarrelOopContinueFrequency =
metric.tripleBarrelOopContinues / (metric.tripleBarrelOopChallenges || 1);
metric.tripleBarrelFrequency =
metric.tripleBarrelAttempts / (metric.tripleBarrelOpportunities || 1);
metric.tripleBarrelTakedownFrequency =
metric.tripleBarrelTakedowns / (metric.tripleBarrelAttempts || 1);
metric.tripleBarrelFoldFrequency =
metric.tripleBarrelFolds / (metric.tripleBarrelChallenges || 1);
metric.tripleBarrelContinueFrequency =
metric.tripleBarrelContinues / (metric.tripleBarrelChallenges || 1);
// Squeeze
metric.squeezeIpFrequency = metric.squeezeIpAttempts / (metric.squeezeIpOpportunities || 1);
metric.squeezeOopFrequency = metric.squeezeOopAttempts / (metric.squeezeOopOpportunities || 1);
metric.squeezeIpTakedownFrequency = metric.squeezeIpTakedowns / (metric.squeezeIpAttempts || 1);
metric.squeezeOopTakedownFrequency =
metric.squeezeOopTakedowns / (metric.squeezeOopAttempts || 1);
metric.squeezeIpFoldFrequency = metric.squeezeIpFolds / (metric.squeezeIpChallenges || 1);
metric.squeezeOopFoldFrequency = metric.squeezeOopFolds / (metric.squeezeOopChallenges || 1);
metric.squeezeIpContinueFrequency = metric.squeezeIpContinues / (metric.squeezeIpChallenges || 1);
metric.squeezeOopContinueFrequency =
metric.squeezeOopContinues / (metric.squeezeOopChallenges || 1);
metric.squeezeFrequency = metric.squeezeAttempts / (metric.squeezeOpportunities || 1);
metric.squeezeTakedownFrequency = metric.squeezeTakedowns / (metric.squeezeAttempts || 1);
metric.squeezeFoldFrequency = metric.squeezeFolds / (metric.squeezeChallenges || 1);
metric.squeezeContinueFrequency = metric.squeezeContinues / (metric.squeezeChallenges || 1);
// Steal
metric.stealIpFrequency = metric.stealIpAttempts / (metric.stealIpOpportunities || 1);
metric.stealOopFrequency = metric.stealOopAttempts / (metric.stealOopOpportunities || 1);
metric.stealIpTakedownFrequency = metric.stealIpTakedowns / (metric.stealIpAttempts || 1);
metric.stealOopTakedownFrequency = metric.stealOopTakedowns / (metric.stealOopAttempts || 1);
metric.stealIpFoldFrequency = metric.stealIpFolds / (metric.stealIpChallenges || 1);
metric.stealOopFoldFrequency = metric.stealOopFolds / (metric.stealOopChallenges || 1);
metric.stealIpContinueFrequency = metric.stealIpContinues / (metric.stealIpChallenges || 1);
metric.stealOopContinueFrequency = metric.stealOopContinues / (metric.stealOopChallenges || 1);
metric.stealFrequency = metric.stealAttempts / (metric.stealOpportunities || 1);
metric.stealTakedownFrequency = metric.stealTakedowns / (metric.stealAttempts || 1);
metric.stealFoldFrequency = metric.stealFolds / (metric.stealChallenges || 1);
metric.stealContinueFrequency = metric.stealContinues / (metric.stealChallenges || 1);
// Donk Bet
metric.donkBetFrequency = metric.donkBetAttempts / (metric.donkBetOpportunities || 1);
metric.donkBetTakedownFrequency = metric.donkBetTakedowns / (metric.donkBetAttempts || 1);
metric.donkBetFoldFrequency = metric.donkBetFolds / (metric.donkBetChallenges || 1);
metric.donkBetContinueFrequency = metric.donkBetContinues / (metric.donkBetChallenges || 1);
// Probe Bet
metric.probeBetFrequency = metric.probeBetAttempts / (metric.probeBetOpportunities || 1);
metric.probeBetTakedownFrequency = metric.probeBetTakedowns / (metric.probeBetAttempts || 1);
metric.probeBetFoldFrequency = metric.probeBetFolds / (metric.probeBetChallenges || 1);
metric.probeBetContinueFrequency = metric.probeBetContinues / (metric.probeBetChallenges || 1);
// Float Bet
metric.floatBetFrequency = metric.floatBetAttempts / (metric.floatBetOpportunities || 1);
metric.floatBetTakedownFrequency = metric.floatBetTakedowns / (metric.floatBetAttempts || 1);
metric.floatBetFoldFrequency = metric.floatBetFolds / (metric.floatBetChallenges || 1);
metric.floatBetContinueFrequency = metric.floatBetContinues / (metric.floatBetChallenges || 1);
// Check-Raise
metric.checkRaiseFrequency = metric.checkRaiseAttempts / (metric.checkRaiseOpportunities || 1);
metric.checkRaiseTakedownFrequency =
metric.checkRaiseTakedowns / (metric.checkRaiseAttempts || 1);
metric.checkRaiseFoldFrequency = metric.checkRaiseFolds / (metric.checkRaiseChallenges || 1);
metric.checkRaiseContinueFrequency =
metric.checkRaiseContinues / (metric.checkRaiseChallenges || 1);
// Open Shove
metric.openShoveIpFrequency = metric.openShoveIpAttempts / (metric.openShoveIpOpportunities || 1);
metric.openShoveOopFrequency =
metric.openShoveOopAttempts / (metric.openShoveOopOpportunities || 1);
metric.openShoveIpTakedownFrequency =
metric.openShoveIpTakedowns / (metric.openShoveIpAttempts || 1);
metric.openShoveOopTakedownFrequency =
metric.openShoveOopTakedowns / (metric.openShoveOopAttempts || 1);
metric.openShoveIpFoldFrequency = metric.openShoveIpFolds / (metric.openShoveIpChallenges || 1);
metric.openShoveOopFoldFrequency =
metric.openShoveOopFolds / (metric.openShoveOopChallenges || 1);
metric.openShoveIpContinueFrequency =
metric.openShoveIpContinues / (metric.openShoveIpChallenges || 1);
metric.openShoveOopContinueFrequency =
metric.openShoveOopContinues / (metric.openShoveOopChallenges || 1);
metric.openShoveFrequency = metric.openShoveAttempts / (metric.openShoveOpportunities || 1);
metric.openShoveTakedownFrequency = metric.openShoveTakedowns / (metric.openShoveAttempts || 1);
metric.openShoveFoldFrequency = metric.openShoveFolds / (metric.openShoveChallenges || 1);
metric.openShoveContinueFrequency = metric.openShoveContinues / (metric.openShoveChallenges || 1);
// Shove
metric.shoveIpFrequency = metric.shoveIpAttempts / (metric.shoveIpOpportunities || 1);
metric.shoveOopFrequency = metric.shoveOopAttempts / (metric.shoveOopOpportunities || 1);
metric.shoveIpTakedownFrequency = metric.shoveIpTakedowns / (metric.shoveIpAttempts || 1);
metric.shoveOopTakedownFrequency = metric.shoveOopTakedowns / (metric.shoveOopAttempts || 1);
metric.shoveIpFoldFrequency = metric.shoveIpFolds / (metric.shoveIpChallenges || 1);
metric.shoveOopFoldFrequency = metric.shoveOopFolds / (metric.shoveOopChallenges || 1);
metric.shoveIpContinueFrequency = metric.shoveIpContinues / (metric.shoveIpChallenges || 1);
metric.shoveOopContinueFrequency = metric.shoveOopContinues / (metric.shoveOopChallenges || 1);
metric.shoveFrequency = metric.shoveAttempts / (metric.shoveOpportunities || 1);
metric.shoveTakedownFrequency = metric.shoveTakedowns / (metric.shoveAttempts || 1);
metric.shoveFoldFrequency = metric.shoveFolds / (metric.shoveChallenges || 1);
metric.shoveContinueFrequency = metric.shoveContinues / (metric.shoveChallenges || 1);
return metric;
}
// Helper function to update metrics
function updateMetric(metric: PokerMetrics, stat: StreetStat) {
// Aggregate basic stats
metric.raises += stat.raises;
metric.bets += stat.bets;
metric.calls += stat.calls;
metric.checks += stat.checks;
metric.folds += stat.folds;
metric.allIns += stat.allIns;
metric.aggressions += stat.aggressions;
metric.passivities += stat.passivities;
metric.decisions += stat.decisions;
metric.decisionDuration += stat.decisionDuration;
metric.decisionDurationAverage = metric.decisionDuration / (metric.decisions || 1);
metric.limps += stat.limps;
metric.limpOpportunities += stat.limpOpportunities;
metric.preflopRaiseOpportunities += stat.preflopRaiseOpportunities;
metric.preflopRaises += stat.preflopRaises;
// Base aggressor stats and calculated takedowns
metric.threeBetIpAttempts += stat.threeBetIpAttempts;
metric.threeBetOopAttempts += stat.threeBetOopAttempts;
metric.threeBetIpOpportunities += stat.threeBetIpOpportunities;
metric.threeBetOopOpportunities += stat.threeBetOopOpportunities;
metric.threeBetIpTakedowns += stat.threeBetIpTakedowns;
metric.threeBetOopTakedowns += stat.threeBetOopTakedowns;
metric.threeBetOpportunities += stat.threeBetIpOpportunities + stat.threeBetOopOpportunities;
metric.threeBetAttempts += stat.threeBetIpAttempts + stat.threeBetOopAttempts;
metric.threeBetTakedowns += stat.threeBetIpTakedowns + stat.threeBetOopTakedowns;
metric.fourBetIpAttempts += stat.fourBetIpAttempts;
metric.fourBetOopAttempts += stat.fourBetOopAttempts;
metric.fourBetIpOpportunities += stat.fourBetIpOpportunities;
metric.fourBetOopOpportunities += stat.fourBetOopOpportunities;
metric.fourBetIpTakedowns += stat.fourBetIpTakedowns;
metric.fourBetOopTakedowns += stat.fourBetOopTakedowns;
metric.fourBetOpportunities += stat.fourBetIpOpportunities + stat.fourBetOopOpportunities;
metric.fourBetAttempts += stat.fourBetIpAttempts + stat.fourBetOopAttempts;
metric.fourBetTakedowns += stat.fourBetIpTakedowns + stat.fourBetOopTakedowns;
metric.fiveBetIpAttempts += stat.fiveBetIpAttempts;
metric.fiveBetOopAttempts += stat.fiveBetOopAttempts;
metric.fiveBetIpOpportunities += stat.fiveBetIpOpportunities;
metric.fiveBetOopOpportunities += stat.fiveBetOopOpportunities;
metric.fiveBetIpTakedowns += stat.fiveBetIpTakedowns;
metric.fiveBetOopTakedowns += stat.fiveBetOopTakedowns;
metric.fiveBetOpportunities += stat.fiveBetIpOpportunities + stat.fiveBetOopOpportunities;
metric.fiveBetAttempts += stat.fiveBetIpAttempts + stat.fiveBetOopAttempts;
metric.fiveBetTakedowns += stat.fiveBetIpTakedowns + stat.fiveBetOopTakedowns;
metric.cbetIpAttempts += stat.cbetIpAttempts;
metric.cbetOopAttempts += stat.cbetOopAttempts;
metric.cbetIpOpportunities += stat.cbetIpOpportunities;
metric.cbetOopOpportunities += stat.cbetOopOpportunities;
metric.cbetIpTakedowns += stat.cbetIpTakedowns;
metric.cbetOopTakedowns += stat.cbetOopTakedowns;
metric.cbetOpportunities += stat.cbetIpOpportunities + stat.cbetOopOpportunities;
metric.cbetAttempts += stat.cbetIpAttempts + stat.cbetOopAttempts;
metric.cbetTakedowns += stat.cbetIpTakedowns + stat.cbetOopTakedowns;
metric.delayedCbetIpAttempts += stat.delayedCbetIpAttempts;
metric.delayedCbetOopAttempts += stat.delayedCbetOopAttempts;
metric.delayedCbetIpOpportunities += stat.delayedCbetIpOpportunities;
metric.delayedCbetOopOpportunities += stat.delayedCbetOopOpportunities;
metric.delayedCbetIpTakedowns += stat.delayedCbetIpTakedowns;
metric.delayedCbetOopTakedowns += stat.delayedCbetOopTakedowns;
metric.delayedCbetOpportunities +=
stat.delayedCbetIpOpportunities + stat.delayedCbetOopOpportunities;
metric.delayedCbetAttempts += stat.delayedCbetIpAttempts + stat.delayedCbetOopAttempts;
metric.delayedCbetTakedowns += stat.delayedCbetIpTakedowns + stat.delayedCbetOopTakedowns;
metric.doubleBarrelIpAttempts += stat.doubleBarrelIpAttempts;
metric.doubleBarrelOopAttempts += stat.doubleBarrelOopAttempts;
metric.doubleBarrelIpOpportunities += stat.doubleBarrelIpOpportunities;
metric.doubleBarrelOopOpportunities += stat.doubleBarrelOopOpportunities;
metric.doubleBarrelIpTakedowns += stat.doubleBarrelIpTakedowns;
metric.doubleBarrelOopTakedowns += stat.doubleBarrelOopTakedowns;
metric.doubleBarrelOpportunities +=
stat.doubleBarrelIpOpportunities + stat.doubleBarrelOopOpportunities;
metric.doubleBarrelAttempts += stat.doubleBarrelIpAttempts + stat.doubleBarrelOopAttempts;
metric.doubleBarrelTakedowns += stat.doubleBarrelIpTakedowns + stat.doubleBarrelOopTakedowns;
metric.tripleBarrelIpAttempts += stat.tripleBarrelIpAttempts;
metric.tripleBarrelOopAttempts += stat.tripleBarrelOopAttempts;
metric.tripleBarrelIpOpportunities += stat.tripleBarrelIpOpportunities;
metric.tripleBarrelOopOpportunities += stat.tripleBarrelOopOpportunities;
metric.tripleBarrelIpTakedowns += stat.tripleBarrelIpTakedowns;
metric.tripleBarrelOopTakedowns += stat.tripleBarrelOopTakedowns;
metric.tripleBarrelOpportunities +=
stat.tripleBarrelIpOpportunities + stat.tripleBarrelOopOpportunities;
metric.tripleBarrelAttempts += stat.tripleBarrelIpAttempts + stat.tripleBarrelOopAttempts;
metric.tripleBarrelTakedowns += stat.tripleBarrelIpTakedowns + stat.tripleBarrelOopTakedowns;
metric.squeezeIpAttempts += stat.squeezeIpAttempts;
metric.squeezeOopAttempts += stat.squeezeOopAttempts;
metric.squeezeIpOpportunities += stat.squeezeIpOpportunities;
metric.squeezeOopOpportunities += stat.squeezeOopOpportunities;
metric.squeezeIpTakedowns += stat.squeezeIpTakedowns;
metric.squeezeOopTakedowns += stat.squeezeOopTakedowns;
metric.squeezeOpportunities += stat.squeezeIpOpportunities + stat.squeezeOopOpportunities;
metric.squeezeAttempts += stat.squeezeIpAttempts + stat.squeezeOopAttempts;
metric.squeezeTakedowns += stat.squeezeIpTakedowns + stat.squeezeOopTakedowns;
metric.stealIpAttempts += stat.stealIpAttempts;
metric.stealOopAttempts += stat.stealOopAttempts;
metric.stealIpOpportunities += stat.stealIpOpportunities;
metric.stealOopOpportunities += stat.stealOopOpportunities;
metric.stealIpTakedowns += stat.stealIpTakedowns;
metric.stealOopTakedowns += stat.stealOopTakedowns;
metric.stealOpportunities += stat.stealIpOpportunities + stat.stealOopOpportunities;
metric.stealAttempts += stat.stealIpAttempts + stat.stealOopAttempts;
metric.stealTakedowns += stat.stealIpTakedowns + stat.stealOopTakedowns;
metric.donkBetAttempts += stat.donkBetAttempts;
metric.donkBetOpportunities += stat.donkBetOpportunities;
metric.donkBetTakedowns += stat.donkBetTakedowns;
metric.donkBetFolds += stat.donkBetFolds;
metric.donkBetContinues += stat.donkBetContinues;
metric.donkBetChallenges += stat.donkBetChallenges;
metric.checkRaiseAttempts += stat.checkRaiseAttempts;
metric.checkRaiseOpportunities += stat.checkRaiseOpportunities;
metric.checkRaiseTakedowns += stat.checkRaiseTakedowns;
metric.checkRaiseFolds += stat.checkRaiseFolds;
metric.checkRaiseContinues += stat.checkRaiseContinues;
metric.checkRaiseChallenges += stat.checkRaiseChallenges;
metric.openShoveIpAttempts += stat.openShoveIpAttempts;
metric.openShoveIpOpportunities += stat.openShoveIpOpportunities;
metric.openShoveIpTakedowns += stat.openShoveIpTakedowns;
metric.openShoveOopAttempts += stat.openShoveOopAttempts;
metric.openShoveOopOpportunities += stat.openShoveOopOpportunities;
metric.openShoveOopTakedowns += stat.openShoveOopTakedowns;
metric.openShoveOpportunities += stat.openShoveIpOpportunities + stat.openShoveOopOpportunities;
metric.openShoveAttempts += stat.openShoveIpAttempts + stat.openShoveOopAttempts;
metric.openShoveTakedowns += stat.openShoveIpTakedowns + stat.openShoveOopTakedowns;
// Base defender stats
metric.threeBetIpChallenges += stat.threeBetIpChallenges;
metric.threeBetOopChallenges += stat.threeBetOopChallenges;
metric.threeBetIpContinues += stat.threeBetIpContinues;
metric.threeBetOopContinues += stat.threeBetOopContinues;
metric.threeBetIpFolds += stat.threeBetIpFolds;
metric.threeBetOopFolds += stat.threeBetOopFolds;
metric.threeBetChallenges += stat.threeBetIpChallenges + stat.threeBetOopChallenges;
metric.threeBetContinues += stat.threeBetIpContinues + stat.threeBetOopContinues;
metric.threeBetFolds += stat.threeBetIpFolds + stat.threeBetOopFolds;
metric.fourBetIpChallenges += stat.fourBetIpChallenges;
metric.fourBetOopChallenges += stat.fourBetOopChallenges;
metric.fourBetIpContinues += stat.fourBetIpContinues;
metric.fourBetOopContinues += stat.fourBetOopContinues;
metric.fourBetIpFolds += stat.fourBetIpFolds;
metric.fourBetOopFolds += stat.fourBetOopFolds;
metric.fourBetChallenges += stat.fourBetIpChallenges + stat.fourBetOopChallenges;
metric.fourBetContinues += stat.fourBetIpContinues + stat.fourBetOopContinues;
metric.fourBetFolds += stat.fourBetIpFolds + stat.fourBetOopFolds;
metric.fiveBetIpChallenges += stat.fiveBetIpChallenges;
metric.fiveBetOopChallenges += stat.fiveBetOopChallenges;
metric.fiveBetIpContinues += stat.fiveBetIpContinues;
metric.fiveBetOopContinues += stat.fiveBetOopContinues;
metric.fiveBetIpFolds += stat.fiveBetIpFolds;
metric.fiveBetOopFolds += stat.fiveBetOopFolds;
metric.fiveBetChallenges += stat.fiveBetIpChallenges + stat.fiveBetOopChallenges;
metric.fiveBetContinues += stat.fiveBetIpContinues + stat.fiveBetOopContinues;
metric.fiveBetFolds += stat.fiveBetIpFolds + stat.fiveBetOopFolds;
metric.cbetIpChallenges += stat.cbetIpChallenges;
metric.cbetOopChallenges += stat.cbetOopChallenges;
metric.cbetIpContinues += stat.cbetIpContinues;
metric.cbetOopContinues += stat.cbetOopContinues;
metric.cbetIpFolds += stat.cbetIpFolds;
metric.cbetOopFolds += stat.cbetOopFolds;
metric.cbetChallenges += stat.cbetIpChallenges + stat.cbetOopChallenges;
metric.cbetContinues += stat.cbetIpContinues + stat.cbetOopContinues;
metric.cbetFolds += stat.cbetIpFolds + stat.cbetOopFolds;
metric.delayedCbetIpChallenges += stat.delayedCbetIpChallenges;
metric.delayedCbetOopChallenges += stat.delayedCbetOopChallenges;
metric.delayedCbetIpContinues += stat.delayedCbetIpContinues;
metric.delayedCbetOopContinues += stat.delayedCbetOopContinues;
metric.delayedCbetIpFolds += stat.delayedCbetIpFolds;
metric.delayedCbetOopFolds += stat.delayedCbetOopFolds;
metric.delayedCbetChallenges += stat.delayedCbetIpChallenges + stat.delayedCbetOopChallenges;
metric.delayedCbetContinues += stat.delayedCbetIpContinues + stat.delayedCbetOopContinues;
metric.delayedCbetFolds += stat.delayedCbetIpFolds + stat.delayedCbetOopFolds;
metric.doubleBarrelIpChallenges += stat.doubleBarrelIpChallenges;
metric.doubleBarrelOopChallenges += stat.doubleBarrelOopChallenges;
metric.doubleBarrelIpContinues += stat.doubleBarrelIpContinues;
metric.doubleBarrelOopContinues += stat.doubleBarrelOopContinues;
metric.doubleBarrelIpFolds += stat.doubleBarrelIpFolds;
metric.doubleBarrelOopFolds += stat.doubleBarrelOopFolds;
metric.doubleBarrelChallenges += stat.doubleBarrelIpChallenges + stat.doubleBarrelOopChallenges;
metric.doubleBarrelContinues += stat.doubleBarrelIpContinues + stat.doubleBarrelOopContinues;
metric.doubleBarrelFolds += stat.doubleBarrelIpFolds + stat.doubleBarrelOopFolds;
metric.tripleBarrelIpChallenges += stat.tripleBarrelIpChallenges;
metric.tripleBarrelOopChallenges += stat.tripleBarrelOopChallenges;
metric.tripleBarrelIpContinues += stat.tripleBarrelIpContinues;
metric.tripleBarrelOopContinues += stat.tripleBarrelOopContinues;
metric.tripleBarrelIpFolds += stat.tripleBarrelIpFolds;
metric.tripleBarrelOopFolds += stat.tripleBarrelOopFolds;
metric.tripleBarrelChallenges += stat.tripleBarrelIpChallenges + stat.tripleBarrelOopChallenges;
metric.tripleBarrelContinues += stat.tripleBarrelIpContinues + stat.tripleBarrelOopContinues;
metric.tripleBarrelFolds += stat.tripleBarrelIpFolds + stat.tripleBarrelOopFolds;
metric.squeezeIpChallenges += stat.squeezeIpChallenges;
metric.squeezeOopChallenges += stat.squeezeOopChallenges;
metric.squeezeIpContinues += stat.squeezeIpContinues;
metric.squeezeOopContinues += stat.squeezeOopContinues;
metric.squeezeIpFolds += stat.squeezeIpFolds;
metric.squeezeOopFolds += stat.squeezeOopFolds;
metric.squeezeChallenges += stat.squeezeIpChallenges + stat.squeezeOopChallenges;
metric.squeezeContinues += stat.squeezeIpContinues + stat.squeezeOopContinues;
metric.squeezeFolds += stat.squeezeIpFolds + stat.squeezeOopFolds;
metric.stealIpChallenges += stat.stealIpChallenges;
metric.stealOopChallenges += stat.stealOopChallenges;
metric.stealIpContinues += stat.stealIpContinues;
metric.stealOopContinues += stat.stealOopContinues;
metric.stealIpFolds += stat.stealIpFolds;
metric.stealOopFolds += stat.stealOopFolds;
metric.stealChallenges += stat.stealIpChallenges + stat.stealOopChallenges;
metric.stealContinues += stat.stealIpContinues + stat.stealOopContinues;
metric.stealFolds += stat.stealIpFolds + stat.stealOopFolds;
metric.openShoveIpChallenges += stat.openShoveIpChallenges;
metric.openShoveOopChallenges += stat.openShoveOopChallenges;
metric.openShoveIpContinues += stat.openShoveIpContinues;
metric.openShoveOopContinues += stat.openShoveOopContinues;
metric.openShoveIpFolds += stat.openShoveIpFolds;
metric.openShoveOopFolds += stat.openShoveOopFolds;
metric.openShoveChallenges += stat.openShoveIpChallenges + stat.openShoveOopChallenges;
metric.openShoveContinues += stat.openShoveIpContinues + stat.openShoveOopContinues;
metric.openShoveFolds += stat.openShoveIpFolds + stat.openShoveOopFolds;
// Shove Defender
metric.shoveIpChallenges += stat.shoveIpChallenges;
metric.shoveOopChallenges += stat.shoveOopChallenges;
metric.shoveIpContinues += stat.shoveIpContinues;
metric.shoveOopContinues += stat.shoveOopContinues;
metric.shoveIpFolds += stat.shoveIpFolds;
metric.shoveOopFolds += stat.shoveOopFolds;
metric.shoveChallenges += stat.shoveIpChallenges + stat.shoveOopChallenges;
metric.shoveContinues += stat.shoveIpContinues + stat.shoveOopContinues;
metric.shoveFolds += stat.shoveIpFolds + stat.shoveOopFolds;
metric.wonAtShowdown += stat.wonAtShowdown;
metric.wonWithoutShowdown += stat.wonWithoutShowdown;
metric.voluntaryPutMoneyInPotTimes += stat.voluntaryPutMoneyInPotTimes;
metric.pot = (metric.pot ?? 0) + (stat.pot ?? 0);
metric.sawFlop = (metric.sawFlop ?? 0) + (stat.sawFlop ?? 0);
metric.winnings += stat.winnings;
metric.returns += stat.returns;
metric.losses += stat.losses;
metric.balance += stat.balance;
metric.profits += stat.profits;
metric.rake += stat.rake;
metric.investments += stat.investments;
metric.won += stat.won;
metric.lost += stat.lost;
metric.startedAt = Math.min(metric.startedAt, stat.createdAt);
metric.gameIds.add(stat.venue + '/' + stat.hand.toString());
metric.distinctGameCount = metric.gameIds.size;
}