use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PlayerStats {
pub total_hands: u64,
pub total_sessions: u64,
pub vpip_hands: u64, pub pfr_hands: u64, pub three_bet_opportunities: u64,
pub three_bet_hands: u64,
pub cbet_opportunities: u64,
pub cbet_hands: u64,
pub fold_to_cbet_opportunities: u64,
pub fold_to_cbet_hands: u64,
pub wtsd_opportunities: u64, pub wtsd_hands: u64,
pub wsd_hands: u64,
pub bets: u64,
pub raises: u64,
pub calls: u64,
pub total_profit_chips: i64,
pub biggest_pot_won: u32,
pub biggest_pot_lost: u32,
}
#[allow(dead_code)]
impl PlayerStats {
pub fn vpip(&self) -> f64 {
if self.total_hands == 0 {
0.0
} else {
self.vpip_hands as f64 / self.total_hands as f64 * 100.0
}
}
pub fn pfr(&self) -> f64 {
if self.total_hands == 0 {
0.0
} else {
self.pfr_hands as f64 / self.total_hands as f64 * 100.0
}
}
pub fn three_bet(&self) -> f64 {
if self.three_bet_opportunities == 0 {
0.0
} else {
self.three_bet_hands as f64 / self.three_bet_opportunities as f64 * 100.0
}
}
pub fn cbet(&self) -> f64 {
if self.cbet_opportunities == 0 {
0.0
} else {
self.cbet_hands as f64 / self.cbet_opportunities as f64 * 100.0
}
}
pub fn fold_to_cbet(&self) -> f64 {
if self.fold_to_cbet_opportunities == 0 {
0.0
} else {
self.fold_to_cbet_hands as f64 / self.fold_to_cbet_opportunities as f64 * 100.0
}
}
pub fn wtsd(&self) -> f64 {
if self.wtsd_opportunities == 0 {
0.0
} else {
self.wtsd_hands as f64 / self.wtsd_opportunities as f64 * 100.0
}
}
pub fn wsd(&self) -> f64 {
if self.wtsd_hands == 0 {
0.0
} else {
self.wsd_hands as f64 / self.wtsd_hands as f64 * 100.0
}
}
pub fn aggression_factor(&self) -> f64 {
if self.calls == 0 {
if self.bets + self.raises > 0 {
99.9 } else {
0.0
}
} else {
(self.bets + self.raises) as f64 / self.calls as f64
}
}
pub fn win_rate_bb_per_100(&self) -> f64 {
if self.total_hands == 0 {
0.0
} else {
self.total_profit_chips as f64 / 2.0 / self.total_hands as f64 * 100.0
}
}
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct StatDefinition {
pub abbrev: &'static str,
pub name: &'static str,
pub explanation: &'static str,
}
pub const STAT_DEFINITIONS: &[StatDefinition] = &[
StatDefinition {
abbrev: "VPIP",
name: "Voluntarily Put $ In Pot",
explanation:
"% of hands where you voluntarily put money in preflop (calls or raises, not blinds)",
},
StatDefinition {
abbrev: "PFR",
name: "Pre-Flop Raise",
explanation:
"% of hands where you raised preflop. Should be close to VPIP for tight-aggressive play",
},
StatDefinition {
abbrev: "3Bet",
name: "3-Bet Frequency",
explanation: "% of times you re-raised when facing a raise. 7-10% is typical",
},
StatDefinition {
abbrev: "Cbet",
name: "Continuation Bet",
explanation: "% of times you bet the flop after raising preflop. 60-70% is standard",
},
StatDefinition {
abbrev: "FCbet",
name: "Fold to C-bet",
explanation: "% of times you folded to a continuation bet. >50% is exploitable",
},
StatDefinition {
abbrev: "WTSD",
name: "Went to Showdown",
explanation: "% of hands that went to showdown when you saw the flop. 25-32% is healthy",
},
StatDefinition {
abbrev: "W$SD",
name: "Won $ at Showdown",
explanation: "% of showdowns you won. >50% means you're showing down strong hands",
},
StatDefinition {
abbrev: "AF",
name: "Aggression Factor",
explanation: "Ratio of (bets + raises) / calls. Higher = more aggressive. 2-3 is typical",
},
];