advent-of-code/2021/src/bin/day17.rs

98 lines
2.6 KiB
Rust
Raw Normal View History

2021-12-17 12:32:46 +01:00
#![feature(core_intrinsics)]
2021-12-17 12:01:43 +01:00
#![feature(test)]
extern crate test;
2021-12-17 12:32:46 +01:00
use std::{intrinsics::unlikely, ops::RangeInclusive};
2021-12-17 12:01:43 +01:00
type TargetArea = (RangeInclusive<isize>, RangeInclusive<isize>);
type Probe = ((isize, isize), (isize, isize));
#[derive(Debug, PartialEq)]
enum ProbeStatus {
Hit,
Miss,
NoLongerReachable,
}
2021-12-17 13:26:10 +01:00
fn calc_status(((xvel, _), (x, y)): &Probe, (xtarget, ytarget): &TargetArea) -> ProbeStatus {
2021-12-17 12:01:43 +01:00
if xtarget.contains(x) && ytarget.contains(y) {
ProbeStatus::Hit
2021-12-17 13:26:10 +01:00
} else if y < ytarget.start() || x > xtarget.end() || (xvel == &0 && !xtarget.contains(x)) {
2021-12-17 12:01:43 +01:00
ProbeStatus::NoLongerReachable
} else {
ProbeStatus::Miss
}
}
fn step(((xvel, yvel), (x, y)): Probe) -> Probe {
((xvel - xvel.signum(), yvel - 1), (x + xvel, y + yvel))
}
2021-12-17 13:26:10 +01:00
fn parse_input() -> TargetArea {
(34..=67, -215..=-186)
}
2021-12-17 12:32:46 +01:00
fn part1(hits: &Vec<((isize, isize), isize)>) -> isize {
*hits.iter().map(|(_, y)| y).max().unwrap()
2021-12-17 12:01:43 +01:00
}
2021-12-17 12:32:46 +01:00
fn find_hits(target: &TargetArea) -> Vec<((isize, isize), isize)> {
2021-12-17 12:51:01 +01:00
(1..=*target.0.end())
.flat_map(move |x| (*target.1.start()..250).map(move |y| (x, y)))
2021-12-17 12:32:46 +01:00
.filter_map(|(xstart, ystart)| {
2021-12-17 12:01:43 +01:00
let mut probe = ((xstart, ystart), (0, 0));
2021-12-17 12:32:46 +01:00
let mut y_high = 0;
2021-12-17 12:01:43 +01:00
loop {
probe = step(probe);
2021-12-17 12:32:46 +01:00
if unlikely(probe.0 .1 == 0) {
y_high = probe.1 .1;
}
2021-12-17 12:01:43 +01:00
match calc_status(&probe, target) {
2021-12-17 12:32:46 +01:00
ProbeStatus::Hit => return Some(((xstart, ystart), y_high)),
2021-12-17 13:26:10 +01:00
ProbeStatus::Miss => continue,
2021-12-17 12:32:46 +01:00
ProbeStatus::NoLongerReachable => return None,
2021-12-17 12:01:43 +01:00
}
}
2021-12-17 12:32:46 +01:00
})
.collect()
2021-12-17 12:01:43 +01:00
}
fn main() {
let target = parse_input();
let hits = find_hits(&target);
2021-12-17 12:32:46 +01:00
println!("Part 1: {}", part1(&hits));
println!("Part 2: {}", hits.len());
2021-12-17 12:01:43 +01:00
}
#[cfg(test)]
mod tests {
use super::*;
use aoc2021::*;
#[test]
fn part1_test() {
let input = (20..=30, -10..=-5);
let hits = find_hits(&input);
2021-12-17 12:32:46 +01:00
assert_eq!(part1(&hits), 45);
2021-12-17 12:01:43 +01:00
}
#[test]
fn part2_test() {
let input = (20..=30, -10..=-5);
let hits = find_hits(&input);
2021-12-17 12:32:46 +01:00
assert_eq!(hits.len(), 112);
2021-12-17 12:01:43 +01:00
}
#[bench]
fn bench_find_hits(b: &mut test::Bencher) {
let input = parse_input();
b.iter(|| assert_eq!(find_hits(&input).len(), 2040))
}
#[bench]
fn bench_part1(b: &mut test::Bencher) {
let input = parse_input();
let hits = find_hits(&input);
2021-12-17 12:32:46 +01:00
b.iter(|| assert_eq!(part1(&hits), 23005))
2021-12-17 12:01:43 +01:00
}
}