Day 17
continuous-integration/drone/push Build is passing Details

main
Julius 2021-12-17 10:08:53 +01:00
parent d2f0553716
commit ad781231e9
Signed by: j00lz
GPG Key ID: AF241B0AA237BBA2
3 changed files with 110 additions and 1 deletions

1
input/day17 Normal file
View File

@ -0,0 +1 @@
target area: x=277..318, y=-92..-53

105
src/day17.rs Normal file
View File

@ -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<Self> {
let c = content.split(' ').skip(1).collect::<Vec<_>>();
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<String> {
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<String> {
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<i32> {
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");
}

View File

@ -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<String> {
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") {