UNPKG

@idealic/poker-engine

Version:

Poker game engine and hand evaluator

1,044 lines (912 loc) 43.7 kB
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; }