Skip to content

Commit

Permalink
Day 21 part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
BakerNet committed Dec 22, 2023
1 parent cfa268a commit 39fd76c
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
| [Day 18](https://adventofcode.com/2023/day/18) | [code](src/bin/18.rs) |||
| [Day 19](https://adventofcode.com/2023/day/19) | [code](src/bin/19.rs) |||
| [Day 20](https://adventofcode.com/2023/day/20) | [code](src/bin/20.rs) |||
| [Day 21](https://adventofcode.com/2023/day/21) | [code](src/bin/21.rs) || - |
| [Day 21](https://adventofcode.com/2023/day/21) | [code](src/bin/21.rs) || |
| [Day 22](https://adventofcode.com/2023/day/22) | [code](src/bin/22.rs) | | |
| [Day 23](https://adventofcode.com/2023/day/23) | [code](src/bin/23.rs) | | |
| [Day 24](https://adventofcode.com/2023/day/24) | [code](src/bin/24.rs) | | |
Expand Down
134 changes: 132 additions & 2 deletions src/bin/21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,40 @@ pub fn valid_neighbors(point: (usize, usize), map: &Vec<Vec<char>>) -> Vec<(usiz
ret
}

pub fn valid_neighbors_p2(point: (usize, usize), map: &Vec<Vec<char>>) -> Vec<(usize, usize)> {
let mut ret = Vec::with_capacity(4);
let width = map.len();
if point.0 % width == 0 {
if map[width - 1][point.1 % width] != '#' {
ret.push((point.0 - 1, point.1));
}
} else if map[point.0 % width - 1][point.1 % width] != '#' {
ret.push((point.0 - 1, point.1));
}
if point.0 % width == width - 1 {
if map[0][point.1 % width] != '#' {
ret.push((point.0 + 1, point.1));
}
} else if map[point.0 % width + 1][point.1 % width] != '#' {
ret.push((point.0 + 1, point.1));
}
if point.1 % width == 0 {
if map[point.0 % width][width - 1] != '#' {
ret.push((point.0, point.1 - 1));
}
} else if map[point.0 % width][point.1 % width - 1] != '#' {
ret.push((point.0, point.1 - 1));
}
if point.1 % width == width - 1 {
if map[point.0 % width][0] != '#' {
ret.push((point.0, point.1 + 1));
}
} else if map[point.0 % width][point.1 % width + 1] != '#' {
ret.push((point.0, point.1 + 1));
}
ret
}

pub fn part_one(input: &str) -> Option<u64> {
let map = input
.lines()
Expand Down Expand Up @@ -51,8 +85,104 @@ pub fn part_one(input: &str) -> Option<u64> {
}

pub fn part_two(input: &str) -> Option<usize> {
// I actually have no idea how to do part 2
input.find(|_| false)
let map = input
.lines()
.map(|line| line.chars().collect())
.collect::<Vec<Vec<_>>>();
let start = map
.iter()
.enumerate()
.find_map(|(row, v)| {
v.iter()
.enumerate()
.find_map(|(col, c)| if *c == 'S' { Some(col) } else { None })
.map(|col| (row, col))
})
.expect("There should be a starting tile.");

assert_eq!(map.len(), map[0].len());
assert_eq!(start.0, map.len() / 2);

let width = map.len();
let to_edge = width - start.0 - 1;
let start = (start.0 + width * 7, start.1 + width * 7);

// Map is divided into 8 right triangles
// The start is the stat is the center
// By travelling to the edge, you fill in one diamond (4 triangles)
// After reaching edge, every width steps you add a new ring of diamonds
//
// To demonstrate, imagine the map is rotated 45 degrees, so you complete squares instead of
// diamonds
//
// afer to_edge steps: 1 diamond
// .....
// .....
// ..#..
// .....
// .....
//
// after to_edge + width steps: 9 diamonds
// .....
// .###.
// .###.
// .###.
// .....
//
// after to_edge + width * 2 steps: 27 diamonds
// #####
// #####
// #####
// #####
// #####
//
// etc.
//
// Theory: The growth from one set of diamonds to the next stabilizes after a few sets
//
let (_, diamond_plots) = (1..(to_edge + width * 3) + 1).fold(
(
vec![start].iter().copied().collect::<HashSet<_>>(),
Vec::new(),
),
|mut acc, i| {
let mut new_acc = HashSet::new();
acc.0.iter().for_each(|point| {
let mut neighbors = valid_neighbors_p2(*point, &map);
neighbors.drain(0..).for_each(|p| {
new_acc.insert(p);
});
});
if i >= to_edge && (i - to_edge) % width == 0 {
acc.1.push(new_acc.len());
}
(new_acc, acc.1)
},
);

let first_diamond = diamond_plots[0]; // to_edge
let nine_diamonds = diamond_plots[1]; // to_edge + width
let twentyfive_diamonds = diamond_plots[2]; // to_edge + width * 2
let thirtysix_diamonds = diamond_plots[3]; // to_edge + width * 3
let diff1 = nine_diamonds - first_diamond;
let diff2 = twentyfive_diamonds - nine_diamonds;
let diff3 = thirtysix_diamonds - twentyfive_diamonds;
assert_ne!(diff1, diff2 - diff1);
assert_eq!(diff2 - diff1, diff3 - diff2);

// Above assertion confirms theory - growth per width steps becomes constant
let transition_growth = diff2 - diff1;

let steps = 26501365;
let mut curr_steps = to_edge + width * 2;
let mut curr_val = twentyfive_diamonds;
let mut growth = diff2;
while curr_steps < steps {
growth += transition_growth;
curr_val += growth;
curr_steps += width;
}
Some(curr_val)
}

#[cfg(test)]
Expand Down

0 comments on commit 39fd76c

Please sign in to comment.