typing_engine/statistics/
multi_target_position_convert.rs1use crate::typing_primitive_types::chunk::key_stroke_candidate::KeyStrokeElementCount;
2use crate::utility::convert_by_weighted_count;
3
4#[cfg(test)]
5mod test;
6
7pub(crate) enum BaseTarget {
8 Chunk,
9 Spell,
10 IdealKeyStroke,
11 KeyStroke,
12}
13
14pub(crate) struct MultiTargetDeltaConverter {
17 base: BaseTarget,
19 spell_count: usize,
21 ideal_key_stroke_count: KeyStrokeElementCount,
23 key_stroke_count: KeyStrokeElementCount,
25}
26
27impl MultiTargetDeltaConverter {
28 pub(crate) fn new(
29 spell_count: usize,
30 ideal_key_stroke_count: KeyStrokeElementCount,
31 key_stroke_count: KeyStrokeElementCount,
32 base: BaseTarget,
33 ) -> Self {
34 assert!(spell_count == 1 || spell_count == 2);
35 assert!(
36 !key_stroke_count.is_double() || (key_stroke_count.is_double() && spell_count == 2)
37 );
38 assert!(
39 !ideal_key_stroke_count.is_double()
40 || (ideal_key_stroke_count.is_double() && spell_count == 2)
41 );
42
43 Self {
44 spell_count,
45 ideal_key_stroke_count,
46 key_stroke_count,
47 base,
48 }
49 }
50
51 pub(crate) fn chunk_delta(&self, base_deltas: &[usize]) -> Vec<usize> {
54 base_deltas.iter().map(|_| 1).collect()
56 }
57
58 pub(crate) fn spell_delta(&self, base_deltas: &[usize]) -> Vec<usize> {
60 match self.base {
61 BaseTarget::Chunk => base_deltas.iter().map(|_| self.spell_count).collect(),
62 BaseTarget::Spell => base_deltas.to_vec(),
63 BaseTarget::IdealKeyStroke => base_deltas
64 .iter()
65 .map(|ideal_key_stroke_delta| {
66 self.ideal_key_stroke_count
67 .convert_key_stroke_delta_to_spell_delta(
68 self.spell_count,
69 *ideal_key_stroke_delta,
70 )
71 })
72 .collect(),
73 BaseTarget::KeyStroke => base_deltas
74 .iter()
75 .map(|key_stroke_delta| {
76 self.key_stroke_count
77 .convert_key_stroke_delta_to_spell_delta(
78 self.spell_count,
79 *key_stroke_delta,
80 )
81 })
82 .collect(),
83 }
84 }
85
86 pub(crate) fn ideal_key_stroke_delta(&self, base_deltas: &[usize]) -> Vec<usize> {
88 match self.base {
89 BaseTarget::Chunk => base_deltas
90 .iter()
91 .map(|_| self.ideal_key_stroke_count.whole_count())
92 .collect(),
93 BaseTarget::Spell => base_deltas
94 .iter()
95 .map(|spell_delta| {
96 self.ideal_key_stroke_count
97 .convert_spell_delta_to_key_stroke_delta(self.spell_count, *spell_delta)
98 })
99 .collect(),
100 BaseTarget::IdealKeyStroke => base_deltas.to_vec(),
101 BaseTarget::KeyStroke => base_deltas
102 .iter()
103 .map(|key_stroke_delta| {
104 convert_between_key_stroke_delta(
105 &self.key_stroke_count,
106 &self.ideal_key_stroke_count,
107 self.spell_count,
108 *key_stroke_delta,
109 )
110 })
111 .collect(),
112 }
113 }
114
115 pub(crate) fn key_stroke_delta(&self, base_deltas: &[usize]) -> Vec<usize> {
117 match self.base {
118 BaseTarget::Chunk => base_deltas
119 .iter()
120 .map(|_| self.key_stroke_count.whole_count())
121 .collect(),
122 BaseTarget::Spell => base_deltas
123 .iter()
124 .map(|spell_delta| {
125 self.key_stroke_count
126 .convert_spell_delta_to_key_stroke_delta(self.spell_count, *spell_delta)
127 })
128 .collect(),
129 BaseTarget::IdealKeyStroke => base_deltas
130 .iter()
131 .map(|key_stroke_delta| {
132 convert_between_key_stroke_delta(
133 &self.ideal_key_stroke_count,
134 &self.key_stroke_count,
135 self.spell_count,
136 *key_stroke_delta,
137 )
138 })
139 .collect(),
140 BaseTarget::KeyStroke => base_deltas.to_vec(),
141 }
142 }
143}
144
145pub(crate) fn convert_between_key_stroke_delta(
147 from: &KeyStrokeElementCount,
148 to: &KeyStrokeElementCount,
149 spell_count: usize,
150 from_delta: usize,
151) -> usize {
152 let pseudo_from_cose = from.construct_pseudo_count_of_spell_elements(spell_count);
153
154 let pseudo_to_cose = to.construct_pseudo_count_of_spell_elements(spell_count);
155
156 let i = pseudo_from_cose.spell_elements_index_of_delta(from_delta);
157
158 let in_spell_element_from_delta = if i == 0 {
159 from_delta
160 } else {
161 assert!(i > 0);
162 from_delta - pseudo_from_cose.key_stroke_count_offset(i)
163 };
164
165 let delta = convert_by_weighted_count(
166 pseudo_from_cose.count_of_spell_elements_index(i),
167 pseudo_to_cose.count_of_spell_elements_index(i),
168 in_spell_element_from_delta,
169 );
170
171 if i > 0 {
172 delta + pseudo_to_cose.key_stroke_count_offset(i)
173 } else {
174 delta
175 }
176}