use std::collections::HashMap; use regex::Regex; fn main() { let input = advent::read_lines(14); println!("14a: {}", winning_distance(&input, 2503)); println!("14b: {}", winning_points(&input, 2503)); } struct Reindeer { name: String, speed: u32, duration: u32, rest: u32, } impl Reindeer { fn new(input: &str) -> Reindeer { let re = Regex::new(r"^([A-Za-z]+) can fly ([0-9]+) km/s for ([0-9]+) seconds, but then must rest for ([0-9]+) seconds.$").unwrap(); let cap = re.captures(input).unwrap(); let name = cap[1].to_string(); let speed = cap[2].parse::().unwrap(); let duration = cap[3].parse::().unwrap(); let rest = cap[4].parse::().unwrap(); Reindeer { name, speed, duration, rest } } fn distance(&self, time: u32) -> u32 { let cycle_time = self.duration + self.rest; let time_flown = (time / cycle_time) * self.duration + std::cmp::min(self.duration, time % cycle_time); time_flown * self.speed } } fn winning_distance(input: &[String], time: u32) -> u32 { input.iter() .map(|line| Reindeer::new(line)) .map(|reindeer| reindeer.distance(time)) .max() .unwrap() } fn winning_points(input: &[String], time: u32) -> u32 { let reindeers = input.iter() .map(|line| Reindeer::new(line)) .collect::>(); let mut scores = HashMap::new(); for t in 1..=time { let mut winner = ("", 0); for reindeer in &reindeers { let distance = reindeer.distance(t); if distance >= winner.1 { winner = (&reindeer.name, distance); } } *scores.entry(winner.0).or_insert(0) += 1; } *scores.values().max().unwrap() } #[cfg(test)] mod tests { use super::*; #[test] fn test() { let input = [ "Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.".to_string(), "Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds.".to_string(), ]; assert_eq!(winning_distance(&input, 1000), 1120); assert_eq!(winning_points(&input, 1000), 689); } }