105 lines
2.8 KiB
Rust
105 lines
2.8 KiB
Rust
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");
|
|
} |