Files
advent/2021/src/day17.rs
2021-12-17 20:41:20 -08:00

108 lines
2.3 KiB
Rust

use advent::prelude::*;
use aoc_runner_derive::aoc;
#[derive(Debug)]
struct Target {
x_min: isize,
x_max: isize,
y_min: isize,
y_max: isize,
}
impl Target {
fn hit(&self, x: isize, y: isize) -> bool {
x >= self.x_min && x <= self.x_max && y >= self.y_min && y <= self.y_max
}
}
fn shoot(x: isize, y: isize, tgt: &Target) -> bool {
let mut x_inc = x;
let mut y_inc = y;
let mut x_cur = 0;
let mut y_cur = 0;
while x_cur <= tgt.x_max && y_cur >= tgt.y_min {
x_cur += x_inc;
y_cur += y_inc;
if x_inc > 0 {
x_inc -= 1;
}
y_inc -= 1;
if tgt.hit(x_cur, y_cur) {
return true;
}
}
false
}
impl FromStr for Target {
type Err = Infallible;
fn from_str(input: &str) -> std::result::Result<Target, Infallible> {
let parts: Vec<_> = input.split(' ').collect();
let x = &parts[2][2..].strip_suffix(',').unwrap();
let y = &parts[3][2..];
let (x_min, x_max) = x
.split_once("..")
.map(|(min, max)| (min.parse().unwrap(), max.parse().unwrap()))
.unwrap();
let (y_min, y_max) = y
.split_once("..")
.map(|(min, max)| (min.parse().unwrap(), max.parse().unwrap()))
.unwrap();
Ok(Target {
x_min,
x_max,
y_min,
y_max,
})
}
}
#[aoc(day17, part1)]
fn part1(input: &str) -> Result<isize> {
let tgt: Target = input.parse()?;
let n = tgt.y_min.abs() - 1;
Ok(n * (n + 1) / 2)
}
#[aoc(day17, part2)]
fn part2(input: &str) -> Result<usize> {
let tgt: Target = input.parse()?;
let mut cnt = 0;
let y_range = tgt.y_min.abs().max(tgt.y_min.abs());
for y in -y_range..=y_range {
for x in 1..=tgt.x_max {
if shoot(x, y, &tgt) {
cnt += 1;
}
}
}
Ok(cnt)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part1() -> Result<()> {
let input = r#"
target area: x=20..30, y=-10..-5
"#
.trim();
assert_eq!(part1(input)?, 45);
Ok(())
}
#[test]
fn test_part2() -> Result<()> {
let input = r#"
target area: x=20..30, y=-10..-5
"#
.trim();
assert_eq!(part2(input)?, 112);
Ok(())
}
}