1
0
Fork 0

day(14): refactor based on Google Chat suggestions

• get rid of the ‹lines›
• simplify free falling check

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-14 17:13:11 +01:00
parent 2ac9103fe2
commit 37a4fca618
Signed by: mfocko
GPG key ID: 7C47D46246790496

View file

@ -21,36 +21,6 @@ struct Line {
to: Coord, to: Coord,
} }
impl Line {
fn direction(&self) -> Coord {
self.to - self.from
}
fn extend_to_x(&self, x: i32) -> Option<Coord> {
let d = self.direction();
match d.x() {
0 => None,
_ => {
let k = (self.from.x() - x) / d.x();
let y = self.from.y() + k * d.y();
Some(Coord::new(x, y))
}
}
}
fn contains(&self, coord: &Coord) -> bool {
let mut xs = [self.from.x(), self.to.x()];
xs.sort();
let mut ys = [self.from.y(), self.to.y()];
ys.sort();
(xs[0]..=xs[1]).contains(&coord.x()) && (ys[0]..=ys[1]).contains(&coord.y())
}
}
#[derive(Debug)] #[derive(Debug)]
struct Multiline { struct Multiline {
lines: BTreeSet<Line>, lines: BTreeSet<Line>,
@ -83,19 +53,11 @@ impl FromStr for Multiline {
} }
} }
fn free_falling(grain: &Coord, lines: &[Line], set: &BTreeSet<Coord>) -> bool { fn can_move(grain: &Coord, set: &BTreeSet<Coord>) -> Option<Coord> {
set.iter().all(|g| g.x() != grain.x() || g.y() < grain.y())
&& lines
.iter()
.filter_map(|l| l.extend_to_x(*grain.x()))
.all(|g| g.y() < grain.y())
}
fn can_move(grain: &Coord, lines: &[Line], set: &BTreeSet<Coord>) -> Option<Coord> {
for direction in [Coord::new(0, 1), Coord::new(-1, 1), Coord::new(1, 1)] { for direction in [Coord::new(0, 1), Coord::new(-1, 1), Coord::new(1, 1)] {
let new_position = *grain + direction; let new_position = *grain + direction;
if !set.contains(&new_position) && lines.iter().all(|l| !l.contains(&new_position)) { if !set.contains(&new_position) {
return Some(new_position); return Some(new_position);
} }
} }
@ -104,18 +66,34 @@ fn can_move(grain: &Coord, lines: &[Line], set: &BTreeSet<Coord>) -> Option<Coor
} }
fn simulate_falling<F>(lines: &Input, terminate: F) -> usize fn simulate_falling<F>(lines: &Input, terminate: F) -> usize
where where
F: Fn(&Coord, &Input, &BTreeSet<Coord>, bool) -> bool F: Fn(&Coord, bool) -> bool,
{ {
let mut grains: VecDeque<Coord> = VecDeque::new(); let mut grains: VecDeque<Coord> = VecDeque::new();
let mut set_grains: BTreeSet<Coord> = BTreeSet::new(); let mut set_grains: BTreeSet<Coord> = BTreeSet::new();
// convert lines to points
for line in lines {
let d = Coord::new(
(line.to.x() - line.from.x()).signum(),
(line.to.y() - line.from.y()).signum(),
);
let mut p = line.from;
while p != line.to {
set_grains.insert(p);
p = p + d;
}
set_grains.insert(p);
}
let lines_count = set_grains.len();
loop { loop {
for i in (0..grains.len()).rev() { for i in (0..grains.len()).rev() {
let grain = grains[i]; let grain = grains[i];
let mut is_set = false; let mut is_set = false;
if let Some(new_grain) = can_move(&grain, lines, &set_grains) { if let Some(new_grain) = can_move(&grain, &set_grains) {
grains[i] = new_grain; grains[i] = new_grain;
} else { } else {
let grain = grains.pop_back().unwrap(); let grain = grains.pop_back().unwrap();
@ -123,8 +101,8 @@ where
is_set = true; is_set = true;
} }
if terminate(&grain, lines, &set_grains, is_set) { if terminate(&grain, is_set) {
return set_grains.len(); return set_grains.len() - lines_count;
} }
} }
@ -142,15 +120,19 @@ impl Solution<Input, Output> for Day14 {
} }
fn part_1(input: &Input) -> Output { fn part_1(input: &Input) -> Output {
fn terminate(grain: &Coord, lines: &Input, set_grains: &BTreeSet<Coord>, _is_set: bool) -> bool { let max_y = *input
free_falling(grain, lines, set_grains) .iter()
} .map(|l| max(l.from.y(), l.to.y()))
.max()
.unwrap();
let terminate = |grain: &Coord, _is_set: bool| *grain.y() >= max_y;
simulate_falling(input, terminate) simulate_falling(input, terminate)
} }
fn part_2(input: &Input) -> Output { fn part_2(input: &Input) -> Output {
fn terminate(grain: &Coord, _lines: &Input, _set_grains: &BTreeSet<Coord>, is_set: bool) -> bool { fn terminate(grain: &Coord, is_set: bool) -> bool {
is_set && grain == &Coord::new(500, 0) is_set && grain == &Coord::new(500, 0)
} }