diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-06 15:01:59 -0600 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-06 15:01:59 -0600 |
commit | 49c163b6002d7694eec3288e3f4de93067bbe116 (patch) | |
tree | 74e9a79bd80a48d8b4e91b9875adcfae178874be /src/day_06.rs | |
parent | 49694b1d007bf8489fa581fe4bd23e8f7e0dc592 (diff) |
feat: impl day 6
Diffstat (limited to 'src/day_06.rs')
-rw-r--r-- | src/day_06.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/day_06.rs b/src/day_06.rs new file mode 100644 index 0000000..2b988a3 --- /dev/null +++ b/src/day_06.rs @@ -0,0 +1,122 @@ +use crate::{Problem, Solution}; + +pub struct Day06; + +impl Problem for Day06 { + const DAY: u8 = 6; + + const INPUT: &'static str = include_str!("../input/day_06.txt"); +} + +impl Solution for Day06 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> anyhow::Result<Self::Answer1> { + let (time, dist) = input.split_once('\n').expect("Invalid input lines"); + let races = time + .split_whitespace() + .skip(1) + .zip(dist.split_whitespace().skip(1)) + .map(TryFrom::try_from) + .try_collect::<Vec<Race>>()?; + + races + .iter() + .map(Race::wins) + .reduce(|acc, n| acc * n) + .ok_or(anyhow::format_err!("Failed to find race")) + } + + fn part_2(input: &str) -> anyhow::Result<Self::Answer2> { + let race: Race = input.parse()?; + Ok(race.wins()) + } +} + +#[derive(Debug)] +struct Race { + time: usize, + dist: usize, +} + +impl Race { + fn run(&self, speed: usize) -> bool { + (speed * (self.time - speed)) > self.dist + } + + fn wins(&self) -> usize { + let mut count = 0; + for speed in 1..self.time { + if self.run(speed) { + count += 1; + } else if count > 0 { + break; + } + } + count + } +} + +impl TryFrom<(&str, &str)> for Race { + type Error = std::num::ParseIntError; + + fn try_from((time, dist): (&str, &str)) -> Result<Self, Self::Error> { + Ok(Self { + time: time.parse()?, + dist: dist.parse()?, + }) + } +} + +impl std::str::FromStr for Race { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (time, dist) = s + .trim() + .split_once('\n') + .ok_or(anyhow::format_err!("Invalid race format"))?; + + let time = time + .strip_prefix("Time: ") + .ok_or(anyhow::format_err!("Invalid time format"))? + .chars() + .filter(|c| *c != ' ') + .collect::<String>() + .trim() + .parse()?; + + let dist = dist + .strip_prefix("Distance: ") + .ok_or(anyhow::format_err!("Invalid distance format"))? + .chars() + .filter(|c| *c != ' ') + .collect::<String>() + .trim() + .parse()?; + + Ok(Race { time, dist }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = indoc::indoc! {" + Time: 7 15 30 + Distance: 9 40 200 + "}; + + #[test] + fn test_part_1() -> anyhow::Result<()> { + Ok(assert_eq!(288, Day06::part_1(INPUT)?)) + } + + #[test] + fn test_part_2() -> anyhow::Result<()> { + Ok(assert_eq!(71503, Day06::part_2(INPUT)?)) + } +} |