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,
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue