flamme_lib/
track.rs

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    ///returns dist from rider to next, and then what's Next
83    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        //down hill
115        let dist = match self.rows[row].hill {
116            Hill::Down => std::cmp::max(dist, 5),
117            _ => dist,
118        };
119        //up hill
120        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        //empty space
137        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                    //slide forward
165                }
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                    //get distance
184                    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}