shuyi_core/bots/playtest/
targets.rs1use alloc::collections::{BTreeMap, BTreeSet};
5use alloc::string::String;
6use alloc::vec::Vec;
7
8use serde::{Deserialize, Serialize};
9
10use super::{Band, Check, Condition, Want};
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
17#[serde(
18 deny_unknown_fields,
19 bound(
20 serialize = "T: Ord + Serialize",
21 deserialize = "T: Ord + Deserialize<'de>"
22 )
23)]
24pub struct Targets<T: Ord> {
25 pub success: BTreeMap<String, Vec<Condition>>,
27 #[serde(default)]
29 pub bands: BTreeMap<T, BTreeMap<String, Band>>,
30 #[serde(default)]
33 pub floors: BTreeMap<String, u32>,
34 #[serde(default)]
36 pub medians: Vec<MedianTarget>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42#[serde(deny_unknown_fields)]
43pub struct MedianTarget {
44 pub entrant: String,
46 pub measure: String,
48 #[serde(default)]
50 pub among: Vec<Condition>,
51 pub want: Want,
53 pub than: String,
55}
56
57impl<T: Ord> Targets<T> {
58 pub fn checks(&self, tier: &T, entrants: &[&str]) -> Vec<Check> {
64 let bands = self.bands.get(tier);
65 let rates = entrants.iter().filter_map(|&name| {
66 let success = self.success.get(name)?;
67 let band = bands?.get(name)?;
68 Some(Check::Rate {
69 entrant: name.into(),
70 success: success.clone(),
71 band: *band,
72 floor: self.floors.get(name).copied(),
73 })
74 });
75 let medians = self
76 .medians
77 .iter()
78 .filter(|m| {
79 entrants.contains(&m.entrant.as_str()) && entrants.contains(&m.than.as_str())
80 })
81 .map(|m| Check::Median {
82 entrant: m.entrant.clone(),
83 measure: m.measure.clone(),
84 among: m.among.clone(),
85 want: m.want,
86 than: m.than.clone(),
87 });
88 rates.chain(medians).collect()
89 }
90
91 pub fn unknown_entrants(&self, known: &[&str]) -> Vec<String> {
94 let named = self
95 .success
96 .keys()
97 .chain(self.bands.values().flat_map(BTreeMap::keys))
98 .chain(self.floors.keys())
99 .chain(self.medians.iter().flat_map(|m| [&m.entrant, &m.than]));
100 named
101 .filter(|name| !known.contains(&name.as_str()))
102 .cloned()
103 .collect::<BTreeSet<String>>()
104 .into_iter()
105 .collect()
106 }
107}