1use std::fmt;
2use termion::color;
3
4#[derive(Copy, Clone, PartialEq, Debug)]
5pub enum Hill {
6 Flat,
7 Up,
8 Down,
9 Finish,
10}
11
12#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub enum RiderType {
14 Sprinter,
15 Rouler,
16}
17
18#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
19pub struct Rider {
20 pub tp: RiderType,
21 pub team: usize,
22}
23
24#[derive(Copy, Clone)]
25pub struct TRow {
26 hill: Hill,
27 riders: [Option<Rider>; 2],
28}
29
30pub struct Track {
31 pub rows: Vec<TRow>,
32}
33
34impl Track {
35 pub fn from_rd(v: Vec<(Hill, usize)>) -> Self {
36 let mut rows = Vec::new();
37 for (hill, n) in v {
38 for _ in 0..n {
39 rows.push(TRow {
40 hill,
41 riders: [None, None],
42 });
43 }
44 }
45 for _ in 0..9 {
46 rows.push(TRow {
47 hill: Hill::Finish,
48 riders: [None, None],
49 });
50 }
51 Track { rows }
52 }
53
54 pub fn add_riders(&mut self, n: usize) {
55 if self.rows.len() < n {
56 return;
57 }
58 for i in 0..n {
59 let r = self.rows.get_mut(i).unwrap();
60 r.riders[0] = Some(Rider {
61 team: i,
62 tp: RiderType::Sprinter,
63 });
64 r.riders[1] = Some(Rider {
65 team: i,
66 tp: RiderType::Rouler,
67 });
68 }
69 }
70
71 pub fn rider_on(&self, r: Rider) -> (usize, Hill) {
72 for (d, h) in self.rows.iter().enumerate() {
73 for i in 0..2 {
74 if h.riders[i] == Some(r) {
75 return (d, h.hill);
76 }
77 }
78 }
79 (0, Hill::Flat)
80 }
81
82 pub fn rider_next(&self, r: Rider) -> (usize, Hill) {
84 let (d_on, h_on) = self.rider_on(r);
85
86 for (d, h) in self.rows[d_on..].iter().enumerate() {
87 if h.hill != h_on {
88 return (d, h.hill);
89 }
90 }
91 (0, Hill::Flat)
92 }
93
94 pub fn dist_to_hill(&self, r: Rider, htype: Hill) -> Option<usize> {
95 let mut dist = None;
96 for row in &self.rows {
97 for n in 0..2 {
98 if row.riders[n] == Some(r) {
99 dist = Some(0);
100 }
101 }
102 if let Some(d) = dist {
103 if row.hill == htype {
104 return Some(d);
105 }
106
107 dist = Some(d + 1);
108 }
109 }
110 None
111 }
112
113 fn calc_new_pos(&self, row: usize, dist: usize) -> (usize, usize) {
114 let dist = match self.rows[row].hill {
116 Hill::Down => std::cmp::max(dist, 5),
117 _ => dist,
118 };
119 let mut first_up = None;
121 for i in 0..dist {
122 let p = i + row;
123 if p >= self.rows.len() {
124 break;
125 }
126 if let Hill::Up = self.rows[row + i].hill {
127 first_up = Some(i);
128 break;
129 }
130 }
131 let dist = match first_up {
132 Some(a) if a <= 5 => std::cmp::min(5, dist),
133 Some(a) => a - 1,
134 None => dist,
135 };
136 for i in 0..dist {
138 let r = row + dist - i;
139 for c in 0..2 {
140 if let None = self.rows[r].riders[c] {
141 return (r, c);
142 }
143 }
144 }
145 return (row, 0);
146 }
147
148 pub fn slipstream(&mut self) {
149 let mut gap = 0;
150 let mut back = None;
151 for i in 0..self.rows.len() {
152 if self.rows[i].hill == Hill::Up {
153 back = None;
154 continue;
155 }
156 if let Some(_) = self.rows[i].riders[0] {
157 if gap == 1 {
158 if let Some(b) = back {
159 for j in (b..i).rev() {
160 self.rows[j].riders = self.rows[j - 1].riders;
161 }
162 self.rows[b].riders = [None, None];
163 }
164 }
166 if back == None {
167 back = Some(i);
168 }
169 gap = 0;
170 continue;
171 }
172 gap += 1;
173 if gap > 1 {
174 back = None
175 }
176 }
177 }
178
179 pub fn move_riders(&mut self, v: &[(usize, usize)]) {
180 for i in (0..self.rows.len()).rev() {
181 for j in 0..2 {
182 if let Some(rd) = self.rows[i].riders[j].clone() {
183 let dist = match v.get(rd.team as usize) {
185 Some((ds, dr)) => match rd.tp {
186 RiderType::Sprinter => *ds,
187 RiderType::Rouler => *dr,
188 },
189 None => 0,
190 };
191 let (nr, nc) = self.calc_new_pos(i, dist);
192 self.rows[nr].riders[nc] = Some(rd);
193 self.rows[i].riders[j] = None;
194 }
195 }
196 }
197 }
198
199 pub fn exhaust(&self) -> Vec<Rider> {
200 let mut res = Vec::new();
201 let mut last = None;
202 for row in &self.rows {
203 match row.riders[0] {
204 Some(_) => {
205 last = Some(row.riders);
206 }
207 None => {
208 if let Some(r) = last {
209 if let Some(v) = r[0] {
210 res.push(v);
211 }
212 if let Some(v) = r[1] {
213 res.push(v);
214 }
215 }
216 last = None;
217 }
218 }
219 }
220 res
221 }
222
223 pub fn winners(&self) -> Vec<Rider> {
224 let mut res = Vec::new();
225 for r in self.rows.iter().filter(|r| r.hill == Hill::Finish) {
226 for i in (0..2).rev() {
227 if let Some(rd) = r.riders[i] {
228 res.push(rd);
229 }
230 }
231 }
232 res
233 }
234
235 pub fn print(&self) {
236 let v = &self.rows;
237
238 for i in 0..(v.len() / 16) + 1 {
239 println!("");
240 let mut lfstr = "".to_string();
241 let mut rtstr = " ".to_string();
242 for h in 0..16 {
243 if let Some(TRow { hill, riders }) = v.get(i * 16 + h) {
244 let c = match hill {
245 Hill::Flat => format!("{}_", color::Bg(color::Reset)),
246 Hill::Up => format!("{}/", color::Bg(color::LightRed)),
247 Hill::Down => format!("{}\\", color::Bg(color::LightBlue)),
248 Hill::Finish => format!("{}^", color::Bg(color::Reset)),
249 };
250 lfstr.push_str(&c);
251 rtstr.push_str(&c);
252 lfstr.push_str(&t_rider_str(riders[1]));
253 rtstr.push_str(&t_rider_str(riders[0]));
254 }
255 }
256 println!("{}", lfstr);
257 println!("{}", rtstr);
258 }
259 }
260}
261
262pub fn team_color(v: usize) -> String {
263 format!(
264 "{}",
265 color::Fg(match v {
266 0 => color::AnsiValue::rgb(5, 0, 0),
267 1 => color::AnsiValue::rgb(0, 5, 0),
268 2 => color::AnsiValue::rgb(0, 0, 5),
269 3 => color::AnsiValue::rgb(5, 0, 5),
270 4 => color::AnsiValue::rgb(0, 5, 5),
271 _ => color::AnsiValue::rgb(5, 5, 0),
272 })
273 )
274}
275
276impl Rider {
277 pub fn rouler(team: usize) -> Rider {
278 Rider {
279 team,
280 tp: RiderType::Rouler,
281 }
282 }
283 pub fn sprinter(team: usize) -> Rider {
284 Rider {
285 team,
286 tp: RiderType::Sprinter,
287 }
288 }
289 pub fn term_color(&self) -> String {
290 team_color(self.team)
291 }
292}
293
294impl fmt::Debug for Rider {
295 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 write!(
297 f,
298 "{}{}{}{}",
299 self.term_color(),
300 self.team,
301 match self.tp {
302 RiderType::Sprinter => 'S',
303 _ => 'R',
304 },
305 color::Fg(color::Reset),
306 )
307 }
308}
309fn t_rider_str(r: Option<Rider>) -> String {
310 r.map(|r| format!("{:?}", r)).unwrap_or("--".to_string())
311}