Dag: 17
Språk: Rust
use std::{iter, str::FromStr};
#[derive(Debug, Default, Clone, Copy)]
pub struct Point(i64, i64);
#[derive(Debug, Default, Clone, Copy)]
pub struct Area {
start: Point,
end: Point,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Probe {
pos: Point,
velocity: Point,
area: Area,
}
impl FromStr for Area {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let r: Vec<_> = s
.split(",")
.flat_map(|s| s.split(".."))
.map(|s| {
s.chars()
.filter(|&c| matches!(c, '0'..='9' | '-'))
.collect::<String>()
})
.filter_map(|s| s.parse::<i64>().ok())
.collect();
Ok(Self {
start: Point(r[0], r[2]),
end: Point(r[1], r[3]),
})
}
}
impl Area {
pub fn check(&self, point: Point) -> bool {
let min_x = self.start.0.min(self.end.0);
let max_x = self.start.0.max(self.end.0);
let min_y = self.start.1.min(self.end.1);
let max_y = self.start.1.max(self.end.1);
min_x <= point.0 && max_x >= point.0 && min_y <= point.1 && max_y >= point.1
}
pub fn range(&self) -> impl Iterator<Item = (i64, i64)> {
let max_x = self.start.0.max(self.end.0);
let min_y = self.start.1.min(self.end.1);
(1..=max_x).flat_map(move |r| iter::repeat(r).zip(min_y..=min_y.abs()))
}
}
impl Probe {
pub fn new(area: Area, velocity: Point) -> Self {
Self {
pos: Default::default(),
velocity,
area,
}
}
pub fn step(&mut self) {
self.pos.0 += self.velocity.0;
self.pos.1 += self.velocity.1;
self.velocity.0 -= self.velocity.0.signum();
self.velocity.1 -= 1;
}
pub fn within_target(&self) -> bool {
self.area.check(self.pos)
}
pub fn bounds_check(&self) -> bool {
let max_x = self.area.start.0.max(self.area.end.0);
let min_y = self.area.start.1.min(self.area.end.1);
max_x < self.pos.0 || min_y > self.pos.1
}
pub fn simulate(&mut self) -> Option<i64> {
let mut max = 0;
while !self.bounds_check() {
max = self.pos.1.max(max);
self.step();
if self.within_target() {
return Some(max);
}
}
None
}
}
pub fn solve(area: Area, mut func: impl FnMut(i64) -> bool) {
for (x, y) in area.range() {
if let Some(value) = Probe::new(area, Point(x, y)).simulate() {
if !func(value) {
return;
}
}
}
}
fn main() {
let area = std::fs::read_to_string("input.txt")
.unwrap()
.lines()
.filter_map(|s| s.parse::<Area>().ok())
.next()
.unwrap();
let mut max = 0;
solve(area, |value| {
max = max.max(value);
if max > value {
return false;
}
true
});
println!("Part 1: {}", max); // 2850
let mut count = 0;
solve(area, |_| {
count += 1;
true
});
println!("Part 2: {}", count); // 1117
}