Optimzed the solution for day 21 and actually calculate the answer for part 2 in code
This commit is contained in:
parent
6aaca41194
commit
295bfed6b4
|
@ -15,8 +15,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part1_test1() -> Result<()> {
|
fn part1_test1() -> Result<()> {
|
||||||
// The example provided uses 6 steps instead of 64, however this should be the correct
|
// The example only provides an answer for 6 steps. (16)
|
||||||
// answer for 64 steps with the example
|
// This should be the correct answer for running the example with 64 steps
|
||||||
Day::test(Day::part1, "test-1", 42)
|
Day::test(Day::part1, "test-1", 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,11 @@ mod tests {
|
||||||
Day::test(Day::part1, "input", 3642)
|
Day::test(Day::part1, "input", 3642)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is no test case for part 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part2_test1() -> Result<()> {
|
fn part2_solution() -> Result<()> {
|
||||||
Day::test(Day::part2, "test-1", 154)
|
Day::test(Day::part2, "input", 608603023105276)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmarks
|
// Benchmarks
|
||||||
|
@ -48,7 +50,7 @@ mod tests {
|
||||||
pub struct Day;
|
pub struct Day;
|
||||||
impl aoc::Solver for Day {
|
impl aoc::Solver for Day {
|
||||||
type Output1 = usize;
|
type Output1 = usize;
|
||||||
type Output2 = usize;
|
type Output2 = isize;
|
||||||
|
|
||||||
fn day() -> u8 {
|
fn day() -> u8 {
|
||||||
21
|
21
|
||||||
|
@ -64,7 +66,7 @@ impl aoc::Solver for Day {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(x, mut c)| {
|
.map(|(x, mut c)| {
|
||||||
if c == 'S' {
|
if c == 'S' {
|
||||||
queue.push(((x as isize, y as isize), 64));
|
queue.push((x as isize, y as isize));
|
||||||
c = '.';
|
c = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,49 +76,35 @@ impl aoc::Solver for Day {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
// Depth first
|
for _ in 0..64 {
|
||||||
while let Some(step) = queue.pop() {
|
while let Some(step) = queue.pop() {
|
||||||
// If we have already evaluated this state, do not add it to the queue
|
for direction in directions {
|
||||||
if visited.contains(&step) {
|
let next = (step.0 + direction.0, step.1 + direction.1);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark this node as visited
|
// If the tile is free add it to the queue
|
||||||
visited.insert(step);
|
if let Some(&tile) = map.get(&next) {
|
||||||
|
if tile == '.' {
|
||||||
// Check if we have ran out of steps
|
set.insert(next);
|
||||||
if step.1 == 0 {
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try moving in all directions
|
|
||||||
for direction in directions {
|
|
||||||
let next = (
|
|
||||||
(step.0 .0 + direction.0, step.0 .1 + direction.1),
|
|
||||||
step.1 - 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
// If the tile is free add it to the queue
|
|
||||||
if let Some(&tile) = map.get(&next.0) {
|
|
||||||
if tile == '.' {
|
|
||||||
queue.push(next);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queue = set.into_iter().collect();
|
||||||
|
set = HashSet::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
visited.iter().filter(|step| step.1 == 0).count()
|
queue.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(input: &str) -> Self::Output2 {
|
fn part2(input: &str) -> Self::Output2 {
|
||||||
let height = input.lines().count();
|
// All maps are square
|
||||||
let width = input.lines().next().unwrap().chars().count();
|
let size = input.lines().count();
|
||||||
println!("{width}, {height}");
|
// Map is square: 131 x 131 => size = 131
|
||||||
// Map is square: 131 x 131
|
// !!! Others have observed 26501365 = 202300 * size + size/2 !!!
|
||||||
// !!! Others have observed 26501365 = 202300 * 131 + 65 !!!
|
// Is there a pattern for i * size + size/2?
|
||||||
// Is there a pattern for i * 131 + 65?
|
|
||||||
// i = 0 => 3776
|
// i = 0 => 3776
|
||||||
// i = 1 => 33652
|
// i = 1 => 33652
|
||||||
// i = 2 => 93270
|
// i = 2 => 93270
|
||||||
|
@ -125,9 +113,9 @@ impl aoc::Solver for Day {
|
||||||
// 3642 - 14737 x + 14871 x^2
|
// 3642 - 14737 x + 14871 x^2
|
||||||
// i = 202300 => 608603023105276
|
// i = 202300 => 608603023105276
|
||||||
// Could not have done this without a hint from Reddit...
|
// Could not have done this without a hint from Reddit...
|
||||||
const N: usize = 2 * 131 + 65;
|
let i: isize = 202300;
|
||||||
|
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = Vec::new();
|
||||||
let map: HashMap<(isize, isize), char> = input
|
let map: HashMap<(isize, isize), char> = input
|
||||||
.lines()
|
.lines()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -136,7 +124,7 @@ impl aoc::Solver for Day {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(x, mut c)| {
|
.map(|(x, mut c)| {
|
||||||
if c == 'S' {
|
if c == 'S' {
|
||||||
queue.push_back(((x as isize, y as isize), 0));
|
queue.push((x as isize, y as isize));
|
||||||
c = '.';
|
c = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,44 +134,41 @@ impl aoc::Solver for Day {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
let mut nums = Vec::new();
|
||||||
|
let mut set = HashSet::new();
|
||||||
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
// Depth first
|
for n in 0..(2 * size + size / 2) {
|
||||||
while let Some(step) = queue.pop_front() {
|
while let Some(step) = queue.pop() {
|
||||||
// If we have already evaluated this state, do not add it to the queue
|
for direction in directions {
|
||||||
if visited.contains(&step) {
|
let next = (step.0 + direction.0, step.1 + direction.1);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark this node as visited
|
let next_wrapped = (
|
||||||
visited.insert(step);
|
next.0.rem_euclid(size as isize),
|
||||||
|
next.1.rem_euclid(size as isize),
|
||||||
|
);
|
||||||
|
|
||||||
// Check if we have ran out of steps
|
// If the tile is free add it to the queue
|
||||||
if step.1 == N {
|
if let Some(&tile) = map.get(&next_wrapped) {
|
||||||
continue;
|
if tile == '.' {
|
||||||
}
|
set.insert(next);
|
||||||
|
}
|
||||||
// Try moving in all directions
|
|
||||||
for direction in directions {
|
|
||||||
let next = (
|
|
||||||
(step.0 .0 + direction.0, step.0 .1 + direction.1),
|
|
||||||
step.1 + 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
let next_wrapped = (
|
|
||||||
next.0 .0.rem_euclid(width as isize),
|
|
||||||
next.0 .1.rem_euclid(height as isize),
|
|
||||||
);
|
|
||||||
|
|
||||||
// If the tile is free add it to the queue
|
|
||||||
if let Some(&tile) = map.get(&next_wrapped) {
|
|
||||||
if tile == '.' {
|
|
||||||
queue.push_back(next);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queue = set.into_iter().collect();
|
||||||
|
set = HashSet::new();
|
||||||
|
|
||||||
|
if n + 1 == nums.len() * size + size / 2 {
|
||||||
|
nums.push(queue.len() as isize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visited.iter().filter(|step| step.1 == N).count()
|
// Using linear algebra these solutions can be found
|
||||||
|
let a = (nums[0] - 2 * nums[1] + nums[2]) / 2;
|
||||||
|
let b = (4 * nums[1] - 3 * nums[0] - nums[2]) / 2;
|
||||||
|
let c = nums[0];
|
||||||
|
|
||||||
|
a * i.pow(2) + b * i + c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user