wowlab_analytics/analytics/
tournament.rs1use serde::Serialize;
2use wowlab_types::{constants::PROTO_DPS_SCALE, proto};
3
4use super::views::AnalyticsView;
5
6#[derive(Clone, Debug, Serialize)]
8#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
9pub struct TournamentView {
10 pub stats: TournamentStatsView,
11 pub top_permutations: Vec<PermutationSummaryView>,
12 pub slot_rankings: Vec<SlotRankingView>,
13}
14
15#[derive(Clone, Debug, Serialize)]
17#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
18pub struct TournamentStatsView {
19 pub winner_dps: f64,
20 pub baseline_dps: f64,
21 pub dps_gain: f64,
22 pub dps_gain_pct: Option<f64>,
23 pub total_permutations: u32,
24 pub total_iterations: u64,
25 pub phases_completed: u32,
26}
27
28#[derive(Clone, Debug, Serialize)]
30#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
31pub struct PermutationSummaryView {
32 pub rank: u32,
33 pub mean_dps: f64,
34 pub ci95_half: f64,
35 pub dps_delta_from_winner: f64,
36 pub diffs: Vec<SlotDiffView>,
37}
38
39#[derive(Clone, Debug, Serialize)]
41#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
42pub struct SlotDiffView {
43 pub slot_index: u32,
44 pub item_id: u32,
45 pub bonus_id_hash: u32,
46}
47
48#[derive(Clone, Debug, Serialize)]
50#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
51pub struct SlotRankingView {
52 pub slot_index: u32,
53 pub items: Vec<SlotItemEntryView>,
54}
55
56#[derive(Clone, Debug, Serialize)]
58#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
59pub struct SlotItemEntryView {
60 pub item_id: u32,
61 pub bonus_id_hash: u32,
62 pub best_perm_dps: f64,
63 pub best_perm_rank: u32,
64 pub ci95_half: f64,
65 pub win_rate_pct: f64,
66 pub marginal_dps_delta: f64,
67}
68
69#[derive(Clone, Debug, Serialize)]
71#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
72#[cfg_attr(feature = "wasm", tsify(into_wasm_abi))]
73#[serde(tag = "kind", rename_all = "snake_case")]
74#[non_exhaustive]
75pub enum JobResultView {
77 Single {
78 analytics: AnalyticsView,
79 },
80 Tournament {
81 analytics: Option<AnalyticsView>,
82 tournament: TournamentView,
83 },
84}
85pub(super) fn convert_slot_diffs(diffs: &[proto::SlotDiff]) -> Vec<SlotDiffView> {
88 diffs
89 .iter()
90 .map(|d| SlotDiffView {
91 slot_index: d.slot_index,
92 item_id: d.item_id,
93 bonus_id_hash: d.bonus_id_hash,
94 })
95 .collect()
96}
97
98pub(super) fn convert_permutation_summaries(
99 summaries: &[proto::PermutationSummary],
100 winner_dps_x10: u32,
101) -> Vec<PermutationSummaryView> {
102 summaries
103 .iter()
104 .map(|s| {
105 let mean_dps = f64::from(s.mean_dps_x10) / PROTO_DPS_SCALE;
106 let winner_dps = f64::from(winner_dps_x10) / PROTO_DPS_SCALE;
107
108 PermutationSummaryView {
109 rank: s.rank,
110 mean_dps,
111 ci95_half: f64::from(s.ci95_half_x10) / PROTO_DPS_SCALE,
112 dps_delta_from_winner: mean_dps - winner_dps,
113 diffs: convert_slot_diffs(&s.diffs),
114 }
115 })
116 .collect()
117}
118
119pub(super) fn convert_slot_rankings(rankings: &[proto::SlotRanking]) -> Vec<SlotRankingView> {
120 rankings
121 .iter()
122 .map(|r| SlotRankingView {
123 slot_index: r.slot_index,
124 items: r
125 .items
126 .iter()
127 .map(|it| SlotItemEntryView {
128 item_id: it.item_id,
129 bonus_id_hash: it.bonus_id_hash,
130 best_perm_dps: f64::from(it.best_perm_dps_x10) / PROTO_DPS_SCALE,
131 best_perm_rank: it.best_perm_rank,
132 ci95_half: f64::from(it.ci95_half_x10) / PROTO_DPS_SCALE,
133 win_rate_pct: f64::from(it.win_rate_x100),
134 marginal_dps_delta: f64::from(it.marginal_dps_delta_x10) / PROTO_DPS_SCALE,
135 })
136 .collect(),
137 })
138 .collect()
139}