diff options
Diffstat (limited to 'src/bin/2021/day17.rs')
-rw-r--r-- | src/bin/2021/day17.rs | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/bin/2021/day17.rs b/src/bin/2021/day17.rs new file mode 100644 index 0000000..54ee4bb --- /dev/null +++ b/src/bin/2021/day17.rs @@ -0,0 +1,106 @@ +use advent_of_code::prelude::*; + +fn fire( + mut xv: i64, + mut yv: i64, + xrange: &std::ops::RangeInclusive<i64>, + yrange: &std::ops::RangeInclusive<i64>, +) -> Option<i64> { + let mut xpos = 0; + let mut ypos = 0; + let mut max_height = 0; + loop { + if xrange.contains(&xpos) && yrange.contains(&ypos) { + return Some(max_height); + } else if (xv >= 0 && xpos > *xrange.end()) + || (xv <= 0 && xpos < *xrange.start()) + || (ypos < *yrange.start()) + { + return None; + } + + xpos += xv; + ypos += yv; + if ypos > max_height { + max_height = ypos; + } + match xv.cmp(&0) { + Ordering::Greater => { + xv -= 1; + } + Ordering::Less => { + xv += 1; + } + _ => {} + } + yv -= 1; + } +} + +pub fn parse( + fh: File, +) -> Result<(std::ops::RangeInclusive<i64>, std::ops::RangeInclusive<i64>)> { + let line = parse::raw_lines(fh).next().unwrap(); + let captures = regex_captures!( + r"target area: x=(-?\d+)..(-?\d+), y=(-?\d+)..(-?\d+)", + &line, + ) + .unwrap(); + let xrange: std::ops::RangeInclusive<i64> = + captures[1].parse().unwrap()..=captures[2].parse().unwrap(); + let yrange: std::ops::RangeInclusive<i64> = + captures[3].parse().unwrap()..=captures[4].parse().unwrap(); + Ok((xrange, yrange)) +} + +pub fn part1( + (xrange, yrange): ( + std::ops::RangeInclusive<i64>, + std::ops::RangeInclusive<i64>, + ), +) -> Result<i64> { + let mut max_height = 0; + for xv in *xrange.start().min(&0)..=*xrange.end().max(&0) { + for yv in *yrange.start().min(&0) + ..=yrange.start().abs().max(yrange.end().abs()) + { + if let Some(height) = fire(xv, yv, &xrange, &yrange) { + if height > max_height { + max_height = height; + } + } + } + } + Ok(max_height) +} + +pub fn part2( + (xrange, yrange): ( + std::ops::RangeInclusive<i64>, + std::ops::RangeInclusive<i64>, + ), +) -> Result<u64> { + let mut count = 0; + for xv in *xrange.start().min(&0)..=*xrange.end().max(&0) { + for yv in *yrange.start().min(&0) + ..=yrange.start().abs().max(yrange.end().abs()) + { + if fire(xv, yv, &xrange, &yrange).is_some() { + count += 1; + } + } + } + Ok(count) +} + +#[test] +fn test() { + assert_eq!( + part1(parse(parse::data(2021, 17).unwrap()).unwrap()).unwrap(), + 5886 + ); + assert_eq!( + part2(parse(parse::data(2021, 17).unwrap()).unwrap()).unwrap(), + 1806 + ); +} |