mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 17:45:02 +01:00
continue
This commit is contained in:
parent
aa651ae78c
commit
43d4458c1a
3 changed files with 119 additions and 45 deletions
9
2023/day10/input_small21.txt
Normal file
9
2023/day10/input_small21.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
...........
|
||||||
|
.S-------7.
|
||||||
|
.|F-----7|.
|
||||||
|
.||.....||.
|
||||||
|
.||.....||.
|
||||||
|
.|L-7.F-J|.
|
||||||
|
.|..|.|..|.
|
||||||
|
.L--J.L--J.
|
||||||
|
...........
|
||||||
9
2023/day10/input_small22.txt
Normal file
9
2023/day10/input_small22.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
..........
|
||||||
|
.S------7.
|
||||||
|
.|F----7|.
|
||||||
|
.||....||.
|
||||||
|
.||....||.
|
||||||
|
.|L-7F-J|.
|
||||||
|
.|..||..|.
|
||||||
|
.L--JL--J.
|
||||||
|
..........
|
||||||
|
|
@ -39,7 +39,6 @@ const BOTTOM_RIGHT: u8 = b'J';
|
||||||
struct Candidates<'a> {
|
struct Candidates<'a> {
|
||||||
v: VecDeque<Candidate>,
|
v: VecDeque<Candidate>,
|
||||||
width: usize,
|
width: usize,
|
||||||
len: usize,
|
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,14 +71,20 @@ fn bottom(pos: usize, len: usize, width: usize) -> Option<usize> {
|
||||||
(pos < (len - width)).then(|| pos + width)
|
(pos < (len - width)).then(|| pos + width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn points_to(byte: u8, direction: Direction) -> bool {
|
||||||
|
match (direction, byte) {
|
||||||
|
(Direction::Left, VERTICAL | TOP_LEFT | BOTTOM_LEFT) => false,
|
||||||
|
(Direction::Right, VERTICAL | TOP_RIGHT | BOTTOM_RIGHT) => false,
|
||||||
|
(Direction::Top, HORIZONTAL | TOP_LEFT | TOP_RIGHT) => false,
|
||||||
|
(Direction::Bottom, HORIZONTAL | BOTTOM_LEFT | BOTTOM_RIGHT) => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Candidates<'_> {
|
impl Candidates<'_> {
|
||||||
fn push(&mut self, new: Candidate) {
|
fn push(&mut self, new: Candidate) {
|
||||||
match (new.came_from, self.bytes[new.pos]) {
|
if points_to(self.bytes[new.pos], new.came_from) {
|
||||||
(Direction::Left, VERTICAL | TOP_LEFT | BOTTOM_LEFT) => {}
|
self.v.push_back(new);
|
||||||
(Direction::Right, VERTICAL | TOP_RIGHT | BOTTOM_RIGHT) => {}
|
|
||||||
(Direction::Top, HORIZONTAL | TOP_LEFT | TOP_RIGHT) => {}
|
|
||||||
(Direction::Bottom, HORIZONTAL | BOTTOM_LEFT | BOTTOM_RIGHT) => {}
|
|
||||||
_ => self.v.push_back(new),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,6 +132,8 @@ struct Loop {
|
||||||
step_map: Vec<(u64, bool)>,
|
step_map: Vec<(u64, bool)>,
|
||||||
target: usize,
|
target: usize,
|
||||||
highest_value: u64,
|
highest_value: u64,
|
||||||
|
width: usize,
|
||||||
|
bytes: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_loop(input: &str) -> Loop {
|
fn get_loop(input: &str) -> Loop {
|
||||||
|
|
@ -145,7 +152,6 @@ fn get_loop(input: &str) -> Loop {
|
||||||
|
|
||||||
let mut cs = Candidates {
|
let mut cs = Candidates {
|
||||||
v: VecDeque::new(),
|
v: VecDeque::new(),
|
||||||
len: bytes.len(),
|
|
||||||
width,
|
width,
|
||||||
bytes: bytes.as_slice(),
|
bytes: bytes.as_slice(),
|
||||||
};
|
};
|
||||||
|
|
@ -158,33 +164,20 @@ fn get_loop(input: &str) -> Loop {
|
||||||
|
|
||||||
let mut highest_value = 0;
|
let mut highest_value = 0;
|
||||||
|
|
||||||
let print = false;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
if print {
|
|
||||||
panic!("cannot test with print");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut target = usize::MAX;
|
let mut target = usize::MAX;
|
||||||
|
|
||||||
while let Some(c) = cs.v.pop_front() {
|
while let Some(c) = cs.v.pop_front() {
|
||||||
if print {
|
print(&step_map, width, |i, (count, seen)| {
|
||||||
for (i, _) in bytes.as_slice().iter().enumerate() {
|
if c.pos == i {
|
||||||
if (i as usize) % width == 0 {
|
print!("NOW ");
|
||||||
println!();
|
} else if cs.v.iter().any(|c| c.pos == i) {
|
||||||
}
|
print!("CAND ");
|
||||||
if c.pos == i {
|
} else if *seen {
|
||||||
print!("NOW ");
|
print!("{:<5} ", count);
|
||||||
} else if cs.v.iter().any(|c| c.pos == i) {
|
} else {
|
||||||
print!("CAND ");
|
print!(". ");
|
||||||
} else if step_map[i].1 {
|
|
||||||
print!("{:<5} ", step_map[i].0);
|
|
||||||
} else {
|
|
||||||
print!(". ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
println!();
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if step_map[c.pos].1 {
|
if step_map[c.pos].1 {
|
||||||
highest_value = highest_value.max(step_map[c.pos].0);
|
highest_value = highest_value.max(step_map[c.pos].0);
|
||||||
|
|
@ -227,24 +220,20 @@ fn get_loop(input: &str) -> Loop {
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if print {
|
print(&step_map, width, |_, (count, seen)| {
|
||||||
for (i, _) in bytes.as_slice().iter().enumerate() {
|
if *seen {
|
||||||
if (i as usize) % width == 0 {
|
print!("{:<5} ", count);
|
||||||
println!();
|
} else {
|
||||||
}
|
print!(". ");
|
||||||
if step_map[i].1 {
|
|
||||||
print!("{:<5} ", step_map[i].0);
|
|
||||||
} else {
|
|
||||||
print!(". ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
println!();
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Loop {
|
Loop {
|
||||||
step_map,
|
step_map,
|
||||||
target,
|
target,
|
||||||
highest_value,
|
highest_value,
|
||||||
|
width,
|
||||||
|
bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,18 +241,83 @@ fn part1(input: &str) -> u64 {
|
||||||
get_loop(input).highest_value
|
get_loop(input).highest_value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surroundings(pos: usize, width: usize, len: usize, byte: u8) -> impl Iterator<Item = usize> {
|
||||||
|
[
|
||||||
|
// TODO: also use these filters in part 1
|
||||||
|
left(pos, width).filter(|_| points_to(byte, Direction::Left)),
|
||||||
|
right(pos, width).filter(|_| points_to(byte, Direction::Right)),
|
||||||
|
top(pos, width).filter(|_| points_to(byte, Direction::Top)),
|
||||||
|
bottom(pos, len, width).filter(|_| points_to(byte, Direction::Bottom)),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum State {
|
||||||
|
Empty,
|
||||||
|
Path,
|
||||||
|
}
|
||||||
|
|
||||||
fn part2(input: &str) -> u64 {
|
fn part2(input: &str) -> u64 {
|
||||||
// Step 1: Find the loop
|
// Step 1: Find the loop
|
||||||
// We do this by using the step-map from before, counting backwards from the target basically.
|
// We do this by using the step-map from before, counting backwards from the target basically.
|
||||||
// Step 2: Cellular-automata-ish, start from the borders and start eating away
|
// Step 2: Cellular-automata-ish, start from the borders and start eating away
|
||||||
// everything connected to that, only stopping at the main loop.
|
// everything connected to that, only stopping at the main loop.
|
||||||
// Open question: How do we squeeze between main loop pipes?
|
// Open question: How do we squeeze between main loop pipes?
|
||||||
let the_loop = get_loop(input);
|
let Loop {
|
||||||
let mut tiles = vec![0; the_loop.step_map.len()];
|
step_map,
|
||||||
|
target,
|
||||||
|
highest_value,
|
||||||
|
width,
|
||||||
|
bytes,
|
||||||
|
} = get_loop(input);
|
||||||
|
let mut tiles = vec![State::Empty; step_map.len()];
|
||||||
|
|
||||||
|
let mut start_surroundings = surroundings(target, width, bytes.len(), bytes[target])
|
||||||
|
.filter(|&pos| step_map[pos].1 && step_map[pos].0 == highest_value - 1);
|
||||||
|
|
||||||
|
tiles[target] = State::Path;
|
||||||
|
|
||||||
|
let mut a = start_surroundings.next().unwrap();
|
||||||
|
let mut b = start_surroundings.next().unwrap();
|
||||||
|
tiles[a] = State::Path;
|
||||||
|
tiles[b] = State::Path;
|
||||||
|
let mut value = highest_value - 1;
|
||||||
|
|
||||||
|
while value > 0 {
|
||||||
|
a = surroundings(a, width, bytes.len(), bytes[a])
|
||||||
|
.find(|&pos| step_map[pos].1 && step_map[pos].0 == value - 1)
|
||||||
|
.unwrap();
|
||||||
|
b = surroundings(b, width, bytes.len(), bytes[b])
|
||||||
|
.find(|&pos| step_map[pos].1 && step_map[pos].0 == value - 1)
|
||||||
|
.unwrap();
|
||||||
|
value -= 1;
|
||||||
|
|
||||||
|
tiles[a] = State::Path;
|
||||||
|
tiles[b] = State::Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&tiles, width, |i, state| match state {
|
||||||
|
State::Empty => print!("{}", bytes[i] as char),
|
||||||
|
State::Path => print!("\x1B[1;31m{}\x1B[1;0m", bytes[i] as char),
|
||||||
|
});
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print<T>(slice: &[T], width: usize, mut cell: impl FnMut(usize, &T)) {
|
||||||
|
if cfg!(not(test)) && cfg!(debug_assertions) {
|
||||||
|
for (i, elem) in slice.iter().enumerate() {
|
||||||
|
if i % width == 0 {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
cell(i, elem);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
helper::tests! {
|
helper::tests! {
|
||||||
day10 Day10;
|
day10 Day10;
|
||||||
part1 {
|
part1 {
|
||||||
|
|
@ -274,6 +328,8 @@ helper::tests! {
|
||||||
"../input.txt" => 6903;
|
"../input.txt" => 6903;
|
||||||
}
|
}
|
||||||
part2 {
|
part2 {
|
||||||
|
"../input_small21.txt" => 4;
|
||||||
|
"../input_small22.txt" => 4;
|
||||||
"../input.txt" => 0;
|
"../input.txt" => 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue