subtr_actor/stats/accumulators/
rush.rs1use super::*;
2
3pub(crate) const RUSH_TEAM_LABELS: [StatLabel; 2] = [
4 StatLabel::new("team", "team_zero"),
5 StatLabel::new("team", "team_one"),
6];
7pub(crate) const RUSH_ATTACKER_LABELS: [StatLabel; 2] = [
8 StatLabel::new("attackers", "2"),
9 StatLabel::new("attackers", "3"),
10];
11pub(crate) const RUSH_DEFENDER_LABELS: [StatLabel; 3] = [
12 StatLabel::new("defenders", "1"),
13 StatLabel::new("defenders", "2"),
14 StatLabel::new("defenders", "3"),
15];
16
17#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
19pub struct RushStats {
20 pub team_zero_count: u32,
21 pub team_zero_two_v_one_count: u32,
22 pub team_zero_two_v_two_count: u32,
23 pub team_zero_two_v_three_count: u32,
24 pub team_zero_three_v_one_count: u32,
25 pub team_zero_three_v_two_count: u32,
26 pub team_zero_three_v_three_count: u32,
27 pub team_one_count: u32,
28 pub team_one_two_v_one_count: u32,
29 pub team_one_two_v_two_count: u32,
30 pub team_one_two_v_three_count: u32,
31 pub team_one_three_v_one_count: u32,
32 pub team_one_three_v_two_count: u32,
33 pub team_one_three_v_three_count: u32,
34 #[serde(default, skip_serializing_if = "LabeledCounts::is_empty")]
35 pub labeled_rush_counts: LabeledCounts,
36}
37
38impl RushStats {
39 pub(crate) fn record(&mut self, event: &RushEvent) {
40 self.labeled_rush_counts.increment(event.labels());
41 self.sync_legacy_counts();
42 }
43
44 pub fn rush_count_with_labels(&self, labels: &[StatLabel]) -> u32 {
45 self.labeled_rush_counts.count_matching(labels)
46 }
47
48 pub fn complete_labeled_rush_counts(&self) -> LabeledCounts {
49 LabeledCounts::complete_from_label_sets(
50 &[
51 &RUSH_TEAM_LABELS,
52 &RUSH_ATTACKER_LABELS,
53 &RUSH_DEFENDER_LABELS,
54 ],
55 &self.labeled_rush_counts,
56 )
57 }
58
59 pub fn with_complete_labeled_rush_counts(mut self) -> Self {
60 self.labeled_rush_counts = self.complete_labeled_rush_counts();
61 self
62 }
63
64 fn team_count(&self, is_team_zero: bool) -> u32 {
65 self.rush_count_with_labels(&[rush_team_label(is_team_zero)])
66 }
67
68 fn matchup_count(&self, is_team_zero: bool, attackers: usize, defenders: usize) -> u32 {
69 self.rush_count_with_labels(&[
70 rush_team_label(is_team_zero),
71 rush_attackers_label(attackers),
72 rush_defenders_label(defenders),
73 ])
74 }
75
76 fn sync_legacy_counts(&mut self) {
77 self.team_zero_count = self.team_count(true);
78 self.team_zero_two_v_one_count = self.matchup_count(true, 2, 1);
79 self.team_zero_two_v_two_count = self.matchup_count(true, 2, 2);
80 self.team_zero_two_v_three_count = self.matchup_count(true, 2, 3);
81 self.team_zero_three_v_one_count = self.matchup_count(true, 3, 1);
82 self.team_zero_three_v_two_count = self.matchup_count(true, 3, 2);
83 self.team_zero_three_v_three_count = self.matchup_count(true, 3, 3);
84 self.team_one_count = self.team_count(false);
85 self.team_one_two_v_one_count = self.matchup_count(false, 2, 1);
86 self.team_one_two_v_two_count = self.matchup_count(false, 2, 2);
87 self.team_one_two_v_three_count = self.matchup_count(false, 2, 3);
88 self.team_one_three_v_one_count = self.matchup_count(false, 3, 1);
89 self.team_one_three_v_two_count = self.matchup_count(false, 3, 2);
90 self.team_one_three_v_three_count = self.matchup_count(false, 3, 3);
91 }
92
93 pub fn for_team(&self, is_team_zero: bool) -> RushTeamStats {
94 if is_team_zero {
95 RushTeamStats {
96 count: self.team_zero_count,
97 two_v_one_count: self.team_zero_two_v_one_count,
98 two_v_two_count: self.team_zero_two_v_two_count,
99 two_v_three_count: self.team_zero_two_v_three_count,
100 three_v_one_count: self.team_zero_three_v_one_count,
101 three_v_two_count: self.team_zero_three_v_two_count,
102 three_v_three_count: self.team_zero_three_v_three_count,
103 }
104 } else {
105 RushTeamStats {
106 count: self.team_one_count,
107 two_v_one_count: self.team_one_two_v_one_count,
108 two_v_two_count: self.team_one_two_v_two_count,
109 two_v_three_count: self.team_one_two_v_three_count,
110 three_v_one_count: self.team_one_three_v_one_count,
111 three_v_two_count: self.team_one_three_v_two_count,
112 three_v_three_count: self.team_one_three_v_three_count,
113 }
114 }
115 }
116}
117
118#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, ts_rs::TS)]
120#[ts(export)]
121pub struct RushTeamStats {
122 pub count: u32,
123 pub two_v_one_count: u32,
124 pub two_v_two_count: u32,
125 pub two_v_three_count: u32,
126 pub three_v_one_count: u32,
127 pub three_v_two_count: u32,
128 pub three_v_three_count: u32,
129}
130
131#[derive(Debug, Clone, Default, PartialEq)]
133pub struct RushStatsAccumulator {
134 stats: RushStats,
135}
136
137impl RushStatsAccumulator {
138 pub fn new() -> Self {
139 Self::default()
140 }
141
142 pub fn stats(&self) -> &RushStats {
143 &self.stats
144 }
145
146 pub fn apply_event(&mut self, event: &RushEvent) {
147 self.stats.record(event);
148 }
149}