solution: day14
This commit is contained in:
		
							
								
								
									
										118
									
								
								src/bin/14.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/bin/14.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | use itertools::Itertools; | ||||||
|  | use lazy_static::lazy_static; | ||||||
|  | use regex::Regex; | ||||||
|  |  | ||||||
|  | lazy_static! { | ||||||
|  |     static ref RE: Regex = Regex::new( | ||||||
|  |         r#"(?P<speed>\d+) km/s for (?P<duration>\d+) seconds, but then must rest for (?P<rest>\d+)"# | ||||||
|  |     ) | ||||||
|  |     .unwrap(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const DISTANCE: u32 = 2503; | ||||||
|  |  | ||||||
|  | struct Reindeer { | ||||||
|  |     speed: u32, | ||||||
|  |     duration: u32, | ||||||
|  |     rest: u32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Reindeer { | ||||||
|  |     fn cycle(&self) -> u32 { | ||||||
|  |         self.duration + self.rest | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn running(&self, traveled: u32) -> bool { | ||||||
|  |         traveled % self.cycle() < self.duration | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<&str> for Reindeer { | ||||||
|  |     fn from(value: &str) -> Self { | ||||||
|  |         let cap = RE.captures(value).unwrap(); | ||||||
|  |  | ||||||
|  |         let speed = cap["speed"].parse().unwrap(); | ||||||
|  |         let duration = cap["duration"].parse().unwrap(); | ||||||
|  |         let rest = cap["rest"].parse().unwrap(); | ||||||
|  |  | ||||||
|  |         Self { | ||||||
|  |             speed, | ||||||
|  |             duration, | ||||||
|  |             rest, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_one(input: &str) -> Option<u32> { | ||||||
|  |     input | ||||||
|  |         .split('\n') | ||||||
|  |         .map(|x| Reindeer::from(x)) | ||||||
|  |         .map(|y| { | ||||||
|  |             ((DISTANCE / y.cycle()) * y.duration | ||||||
|  |                 + vec![DISTANCE % y.cycle(), y.duration].iter().min().unwrap()) | ||||||
|  |                 * y.speed | ||||||
|  |         }) | ||||||
|  |         .max() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug)] | ||||||
|  | struct Scoreboard { | ||||||
|  |     current_distance: u32, | ||||||
|  |     score: u32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Scoreboard { | ||||||
|  |     fn empty() -> Self { | ||||||
|  |         Self { | ||||||
|  |             current_distance: 0, | ||||||
|  |             score: 0, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn part_two(input: &str) -> Option<u32> { | ||||||
|  |     let reindeers = input.split('\n').map(|x| Reindeer::from(x)).collect_vec(); | ||||||
|  |     let mut scoreboards = vec![Scoreboard::empty(); reindeers.len()]; | ||||||
|  |  | ||||||
|  |     for traveled in 0..DISTANCE { | ||||||
|  |         for (idx, r) in reindeers | ||||||
|  |             .iter() | ||||||
|  |             .enumerate() | ||||||
|  |             .filter(|(_, x)| x.running(traveled)) | ||||||
|  |         { | ||||||
|  |             scoreboards[idx].current_distance += r.speed; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let win = scoreboards | ||||||
|  |             .iter() | ||||||
|  |             .map(|x| x.current_distance) | ||||||
|  |             .max() | ||||||
|  |             .unwrap(); | ||||||
|  |  | ||||||
|  |         for r in scoreboards.iter_mut().filter(|x| x.current_distance == win) { | ||||||
|  |             r.score += 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     scoreboards.iter().map(|x| x.score).max() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     let input = &aoc::read_file("inputs", 14); | ||||||
|  |     RE.captures(input); | ||||||
|  |     aoc::solve!(1, part_one, input); | ||||||
|  |     aoc::solve!(2, part_two, input); | ||||||
|  | } | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_one() { | ||||||
|  |         let input = aoc::read_file("test_inputs", 14); | ||||||
|  |         assert_eq!(part_one(&input.trim()), Some(1120)); | ||||||
|  |     } | ||||||
|  |     #[test] | ||||||
|  |     fn test_part_two() { | ||||||
|  |         let input = aoc::read_file("test_inputs", 14); | ||||||
|  |         assert_eq!(part_two(&input.trim()), None); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								src/test_inputs/14.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/test_inputs/14.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds. | ||||||
|  | Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds. | ||||||
		Reference in New Issue
	
	Block a user