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:
parent
2ac9103fe2
commit
37a4fca618
1 changed files with 31 additions and 49 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
where
|
||||
F: Fn(&Coord, &Input, &BTreeSet<Coord>, bool) -> bool
|
||||
where
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue