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,
}
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)]
struct Multiline {
lines: BTreeSet<Line>,
@ -83,19 +53,11 @@ impl FromStr for Multiline {
}
}
fn free_falling(grain: &Coord, lines: &[Line], set: &BTreeSet<Coord>) -> bool {
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> {
fn can_move(grain: &Coord, set: &BTreeSet<Coord>) -> Option<Coord> {
for direction in [Coord::new(0, 1), Coord::new(-1, 1), Coord::new(1, 1)] {
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);
}
}
@ -105,17 +67,33 @@ fn can_move(grain: &Coord, lines: &[Line], set: &BTreeSet<Coord>) -> Option<Coor
fn simulate_falling<F>(lines: &Input, terminate: F) -> usize
where
F: Fn(&Coord, &Input, &BTreeSet<Coord>, bool) -> bool
F: Fn(&Coord, bool) -> bool,
{
let mut grains: VecDeque<Coord> = VecDeque::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 {
for i in (0..grains.len()).rev() {
let grain = grains[i];
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;
} else {
let grain = grains.pop_back().unwrap();
@ -123,8 +101,8 @@ where
is_set = true;
}
if terminate(&grain, lines, &set_grains, is_set) {
return set_grains.len();
if terminate(&grain, is_set) {
return set_grains.len() - lines_count;
}
}
@ -142,15 +120,19 @@ impl Solution<Input, Output> for Day14 {
}
fn part_1(input: &Input) -> Output {
fn terminate(grain: &Coord, lines: &Input, set_grains: &BTreeSet<Coord>, _is_set: bool) -> bool {
free_falling(grain, lines, set_grains)
}
let max_y = *input
.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)
}
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)
}