From ad781231e956297015169ad392942b7141ff3e1e Mon Sep 17 00:00:00 2001 From: Julius de Jeu Date: Fri, 17 Dec 2021 10:08:53 +0100 Subject: [PATCH] Day 17 --- input/day17 | 1 + src/day17.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 5 ++- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 input/day17 create mode 100644 src/day17.rs diff --git a/input/day17 b/input/day17 new file mode 100644 index 0000000..84da003 --- /dev/null +++ b/input/day17 @@ -0,0 +1 @@ +target area: x=277..318, y=-92..-53 \ No newline at end of file diff --git a/src/day17.rs b/src/day17.rs new file mode 100644 index 0000000..cefedfe --- /dev/null +++ b/src/day17.rs @@ -0,0 +1,105 @@ +use std::cmp::Ordering; +use crate::Day; + +pub struct Day17 { + x_min: i32, + x_max: i32, + y_min: i32, + y_max: i32, +} + +impl Day for Day17 { + fn init(content: String) -> anyhow::Result { + let c = content.split(' ').skip(1).collect::>(); + let (x_min, x_max) = c[1][2..(c[1].len() - 1)].split_once("..").unwrap(); + let (y_min, y_max) = c[2][2..].split_once("..").unwrap(); + + Ok(Day17 { + x_min: x_min.parse()?, + x_max: x_max.parse()?, + y_min: y_min.parse()?, + y_max: y_max.parse()?, + }) + } + + fn part1(&self) -> anyhow::Result { + let mut hits = Vec::new(); + for dx in 0..=self.x_max { + for dy in -100..250 { + let points = self.calc((dx, dy)); + if self.hits(&points) { + hits.push(max_height(&points).unwrap()); + } + } + } + Ok(format!("{}", hits.iter().max().unwrap())) + } + + fn part2(&self) -> anyhow::Result { + let mut hits = Vec::new(); + for dx in 0..=self.x_max { + for dy in -100..250 { + let points = self.calc((dx, dy)); + if self.hits(&points) { + hits.push((dx, dy)); + } + } + } + Ok(format!("{}", hits.len())) + } +} + +impl Day17 { + fn hits(&self, points: &[(i32, i32)]) -> bool { + points.iter().any(|&(x, y)| x >= self.x_min && x <= self.x_max && y >= self.y_min && y <= self.y_max) + } + + fn calc(&self, initial_velocity: (i32, i32)) -> Vec<(i32, i32)> { + let mut steps = vec![(0, 0)]; + let mut velocity = initial_velocity; + + loop { + let (x, y) = steps.last().unwrap(); + let (x, y) = (x + velocity.0, y + velocity.1); + if x > self.x_max || y < self.y_min { + break; + } + steps.push((x, y)); + match velocity.0.cmp(&0) { + Ordering::Less => velocity.0 += 1, + Ordering::Equal => {} + Ordering::Greater => velocity.0 -= 1, + } + velocity.1 -= 1; + } + steps + } +} + +fn max_height(points: &[(i32, i32)]) -> Option { + points.iter().map(|&x| x.1).max() +} + +#[cfg(test)] +mod tests { + use crate::{Day, day_tests}; + use crate::day17::Day17; + + const INPUT: &str = "target area: x=20..30, y=-10..-5"; + + #[test] + fn part1_test() -> anyhow::Result<()> { + let d = Day17::init(INPUT.to_string())?; + assert_eq!("45", d.part1()?); + Ok(()) + } + + #[test] + fn part2_test() -> anyhow::Result<()> { + let d = Day17::init(INPUT.to_string())?; + assert_eq!("112", d.part2()?); + Ok(()) + } + + day_tests!(Day17, "17", "4186", "2709"); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6f4245d..d29992b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use crate::day13::Day13; use crate::day14::Day14; use crate::day15::Day15; use crate::day16::Day16; +use crate::day17::Day17; mod day; mod day01; @@ -37,6 +38,7 @@ mod day13; mod day14; mod day15; mod day16; +mod day17; fn load_input(day: &str) -> Result { read_to_string(format!("./input/day{}", day)).map_err(|x| x.into()) @@ -87,7 +89,8 @@ fn main() -> anyhow::Result<()> { Box::new(Day13::init(load_input("13")?)?), Box::new(Day14::init(load_input("14")?)?), Box::new(Day15::init(load_input("15")?)?), - Box::new(Day16::init(load_input("16")?)?),]; + Box::new(Day16::init(load_input("16")?)?), + Box::new(Day17::init(load_input("17")?)?),]; let _verbosity = matches.occurrences_of("v"); if matches.is_present("all") {