This commit is contained in:
Acvaxoort 2023-12-22 02:29:54 +01:00
parent d6efa60716
commit fc5e45dcbf
4 changed files with 413 additions and 0 deletions

7
day21/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day21"
version = "0.1.0"

8
day21/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day21"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

131
day21/input.txt Normal file
View File

@ -0,0 +1,131 @@
...................................................................................................................................
.#........#.#.........#................##.#.............#....................#....#....#.#...#.......#..........#........#.........
....#......#.....................##...#.#....#.#..#...#.......................#.....#..........##....#..#........#.##..#..#...#....
.#.....#.............#.#...............#...........#.#.#................#...........#.#.....#.......##......#........#.#...........
.....#...........#.......##.#.#..........#....#....#..#.#..................................#....##...#.#.....#..#.......#...#...#..
...#....##............#...#..#.....#....##....#....##...........#...............#..##..#..............#..#......#.....#............
..##....#.........#.......#..#...#...........................................#.....#.#........#...#.......................#.....#..
..##.#........#..........#......#...#.....#..#.......#........................#..........##......#...#.#..............#......#.....
........#....##.................................#.##.........#.......#........#...#..#.....................#.#.##....#.........#...
.#...............#....#..........#....#.#...........................................................#.#.....#...#...#.........#....
..#........#.##..............#...##.....#..#...#....................................#..##......#..#.......#........................
...........................................#.................#.#..................#..#..#..#....#..#................#..........#...
.....#...#...#.#......#.....#.#.....#.#..#........................#..#.##...................#.................................#.#..
......#...........#.........##....#.#.#....#..............#........#....................#.............#..##...#.............#......
..#...........##....#......#..#........................#.#........#..#...#...........#............................#.#............#.
.#....#..#......#..........................#.......................#....#...........#......#.......#...............................
....#.#...##....#.........#....#...#.#..#............................#.......#...............................................#..#..
.......#..........##......#..#...#.....#............#...#...................#...............#..#..................#.....#..#...#...
..................#.........#....#.#....#..#....................#..................................................................
.#.##.................#....#..#.......##.#.................#.#............#...#..........#.#...#.........##.#...............#......
..#........#.....#.#.........#.#.....#..#........#...#.....#....#....#.....................##....#...............................#.
..#...#....#.#.............#..#..#...............##.......##.........#.....................................#....###.....##....#....
....#..####.....#....................#................#.......#.............#..#..#..........##......##.......#...........#........
..........##..#........#.......#..............#.#......#..#....#.............#...#................#......##...#..#......#..........
......#....#...#........#.............................##..#.....#..............#.#......................................##.#...#...
.#..........................................#.......#...#.##..#............#.......................#.#...##........................
............#.#...........#.....#....................##...#...#....#.................#.#.........#......#........#......#...#......
.#.....##.#..#..........#....##............#...........#.#.....#.......#............#.#............#...............................
.........#........#...#.###.....#.........#.#...##.##....##..........#................................#..........#...##...#........
...........#.........##...#.#..................................................#.........#..................#.........#.......#....
....##...#..#.#..#.......................#....#......#............#....#.........###......#..............#.......#...#..........#..
...........#.......#......#...............................#.....#.......#..#...............#.........##........#.#.........#.......
......#....#.................#..............#..#..........#...#........................##..............#.........................#.
.###.##...#.##........#........................#.#.###................#...#.#....#...........#...............##.........#..........
...........................................#.........#..##.................#...#.#.#..##..#............#.#.#.....##.....#..........
.#............................................#..#............#....#...#...#......#.#..........................#....#.#..........#.
...........#...........#................#........#..........#........#...........#..............#.........#....##....#....#...##.#.
................#............................#...#......#.....................#..............#.........................##..#...#...
...#....#.............................................#..................#.....#.#..#.....#................#.......#....#..........
.#....##..#.#.......#.............#..............#...#..#....................#..#........#.#.......................................
.#...#.......................................................#..........#.........#.......##...#.#.#............###............#.#.
.....#.....#......#..............#.#...............#....#.....................#......#....#.#........#.........#....#.........#....
............#.#.###.......................................................#...................#....#...#.......##............#.....
.#......#..............................#..........#....#....#.#.#........#............#.....#........................#......#......
................#......................##.......#.......#..#..............##...................#...#...#...........................
.#...#..................#.......................#...#...#..........#.......#.......#...................##...................#......
........#...............#...#....................#..#.......................#.............#.#.#..........#..........###........#.#.
.#..##...#..#............#.....#.....................#......#..............#......#..#..............#.....................#........
....#...###.....................###..........#....#....#..............#................#.#.......#.#....##............#......#.#...
......#.....................#.......#.#.#...#....#...#.#.....#..#........##.#..#..#......##........................................
.......#.#............#...........#........#..............#....##..##..................##..........#...........#.......#..#..#...#.
..#..#......................#..................................#....#......#...#............##......#......................##...#..
.#...............................#.#.........#.....................###.#..................##.#...#.......#....................#..#.
......##................#.........#......#................#........#.....#....#.#.##..#..#...##...#.#...........#................#.
..#..#.........#...............##..................#........................................#........#......##.....................
...................#....#......#...................#.#.....#..............#....##................#......#...#......#.........#.....
....#...........#.......#......#..........#.....................#..#.........##.....##...........###......##.......................
.................#..#....#..##.........................................#......#..........#............#..#....#.................#..
.............#..#........#..#..#.#.......#..........#...........#..#.........#.#...................###.....#.......................
..#............#..#..#..#..................#.##.#...#.#...#............###......#........................#.........#..#.........#..
...........#..##.#..#.............#...#.............#.........#.....#.......#..................#...##..##......#...#..#............
..............#...#...#.....##....#.#........#................#.....#.....#......#.......##....#.....#......#..#....#..............
.............#....#..##..#.................#....#.#......#.#......#...##.....#....###.......#.......#..............................
............................#..........#.......#................#....#.........#.......#.#..................#......................
..........#...#.......#......................................##..........#..#......#............#..............#.....#..#..........
.................................................................S.................................................................
................#.........#.....#........#......................#....#.#.............#....#...#.............#...........#..........
.........................................#......#............#...........#.......#......#..##.........##.............#.............
........#................#.......#..........#.....#..........#........#.................##......#.............#.....#.....#........
........#........#......#.......#....#...##.....................#.........#.....#.........#.................#..#...................
.............#............................#.......#......#...##.........##...#......#.....#.#...#....................#.............
..................................................#......#.......................#..##..#...##........#.#........#.................
.#...........#..#.......#.....#...............#...#.....#..........#...#.#.#.......#.#..........................#.#................
.####...............#...........#......#..#...................#....#....#...........#...#...................#.................#.#..
...............#......#.##...............##..#..#........#..........#.#.............##......#............#...#.....#............#..
.......................#.....###..#....#..#........................................#.#.............#...#........#..................
.....................##....#...............#.........#....#.####...#......#.................#.#...........#......##..........#.#...
..................#.................###...#............................#.#...##..#.#.#..#...#.................................#..#.
....................#..........#..............#............................#.......#.........................#................#....
.#..#...............#.........#..#..........#...#..........##.......##.##.....#....#...#.#......#...##.#...........................
....#...............#....#.............................#.....#.........#..............#......#..............#............#.......#.
........................#...........#..........#...#............#...#.#....#.............##..............##.#...................#..
...#..................#.#...#...#.........#...........#.....#...#.##........#.#....#..........#.......##...........................
.........#.#..........##.#....................#....#................#..#.#.....#...........#.........####.............#.......##...
.#......#...................#........#.......#........#...#..#..........#..##..#..........#........................................
.....#....#..#................##.....#......#.........................#.###...................#..#................#..#......#......
..............#..........................................#.........#.....##.###............#...##.....................##...........
..#......#..#.#.#.........#...#....................#.........#.........#......#...#.....................................#..........
.......#...#.................#..........................#...##..#...#.#.........##............#..................#...............#.
....#.........#.............#.......#.#..........#................#..##.#.#.#...................#.....#............#.....##....#...
.###...............................#.........#..............#.#......#......#.....##.#.#.......#................#.#..............#.
...#........#......#........................#.......#.##...#.........#........#...#.......#..##....#...........#....#..##..........
......#.......#........#.......#..#...#....#.......#....#.#..........##........#..#...............#.......................##..#....
...................#....#..........#........#.............#...#...##...#..........#.......#...#............#..........##...........
.#........##......#.#................#.....#..........#....###................#.....#.......###...............#...#..........#..#..
...#.........#...#....#............#..................##....#......#.....#.......#..........#...#...........#.....#..#.......#.....
........#.................#........#.........#...............#...........#.##...##.......#..................#.......#....##........
.###......#.....#......#.....................##..#...#........#........#....#................................#....#.....#.#........
...........##..............................#..#...........#....#...#......#.#..#......#...............#............................
.....#.#..#.........#............................#.....#.#.##......#.#.........#.....#.#...........................#...##......#.#.
..............#.#.#.....#.#.............#..#.#.....#....#..#.#....#.................#....................#..........#........#.....
..........#.....##.......#................#....................................#..#......#.........#..............#...#......##....
.##.#......###..............#.#...............###......#.................#.......#......#.............................#....#.#.....
..#..#...#............#....##.............#........................#.#..................................#......................#...
......#.....#.............#...#............#....#.......#.....#.................................#..##...#.#..............#.........
...........#..........#..#.#..................##...........#.......#........#....#.............#....................#.....#........
....#...........#........##........................................#.#...............#.............#.#...##...#........#...........
...#..#..............................................................#...#.#...#..#...........#..#..#....#..#..#.......#..#........
...................#.#.....##...........................#................#.#...#...........#.............................#.........
.....###.........#.....#...#...##...#..#........###.....#..#..............#.....#...................#...#...........#...#..........
..............#......................................#..#....#.........##....##..#.......#.......................#.....##..........
..#...................#...........#................................#.....#.#.#..........................#....#......#......#.......
..#......#....#..##..#....#............#...........###........................#.........#........#........#............#.........#.
...................#.##...........#....#..##............#...................#.........#........##........#...........#.#...........
...#.#......#....#........#.......#....................................#.##..#.........#....#.#.....#.........................#..#.
....#.#...#...........................................#...#..#....#....#..............#.........................#.....#......#..#..
......#..................#..........#..#....#.......................#...............#...........#..............#....#.#............
.#..............#........##......#...#....#...#.#................................................#.....##....#...##...#.#........#.
.........#.............#..#..#...........................#.............#...........................#....##............#............
..........#...#.....#..#...#...........#.#.......#........#.....................#.....#.....#...#.#..#......#....#....#...#..#.....
.#........#............##.................##...............#.....................#.##.................#........#......#............
....#........##....#..#.#.........#................................#................#.#.....#.............#..#....##.#....##.......
........#.#.....#.......#.#..##..............##...................#...................#..#....................#..#.......#...#.##..
.....#.#.........#.#....###..#..#.......#.....#................#....#........#.....................#.###.....#...........#......#..
......#...#................#..#...##............#......#...................#............................#.........#....##...##.....
..........#...##.....#....#...........#.....#......#..#.......................##...#.##.....#...#..##...#...#..#..#..........#...#.
......#............#...........#.#..#...............#.............................#..#.......#...#.................#.......#....#..
..............#........#............#....#.....##...#.###...................#............#..#.#..................#.............#...
.............#....#.......#..#......#....#...#..#.......##.............#.##...#.........#..........................#.#...........#.
.#..............#...#......#.......#..#................#.#.............#....#...............#.......#..............................
...................................................................................................................................

267
day21/src/main.rs Normal file
View File

@ -0,0 +1,267 @@
use std::mem;
use std::fs::read_to_string;
use std::time::Instant;
// Solution to part 1 and helper for part 2
fn count_options_basic(layout: &Vec<&[u8]>, start_pos: (i32, i32), steps: i32) -> u64 {
count_options_basic_cont(layout, start_pos, steps, false)
}
// Like count_options_basic but can begin as if we're already on an odd number
fn count_options_basic_cont(layout: &Vec<&[u8]>, start_pos: (i32, i32), steps: i32, count_odd: bool) -> u64 {
if steps < 0 {
return 0;
}
let modulo_equal = (steps + if count_odd { 1 } else { 0 }) % 2;
let width = layout[0].len();
let height = layout.len();
let mut visited: Vec<Vec<bool>> = vec![vec![false; width]; height];
let mut tile_queue: Vec<(i32, i32)> = vec![start_pos];
visited[start_pos.1 as usize][start_pos.0 as usize] = true;
let mut sum = (1 - modulo_equal) as u64;
let mut next_tile_queue: Vec<(i32, i32)> = vec![];
for step in 1..=steps {
let mut try_tile = |x: i32, y: i32| {
if layout[y as usize][x as usize] != b'#' {
if !visited[y as usize][x as usize] {
visited[y as usize][x as usize] = true;
next_tile_queue.push((x, y));
if step % 2 == modulo_equal {
sum += 1;
}
}
}
};
for &(x, y) in &tile_queue {
if x > 0 {
try_tile(x - 1, y);
}
if x < width as i32 - 1 {
try_tile(x + 1, y);
}
if y > 0 {
try_tile(x, y - 1);
}
if y < height as i32 - 1 {
try_tile(x, y + 1);
}
}
if next_tile_queue.is_empty() {
break;
}
tile_queue.clear();
mem::swap(&mut tile_queue, &mut next_tile_queue);
}
sum
}
// Not used in the end but helped figure out the better solution, also has commented visualisation
fn count_options_infinite_naive(layout: &Vec<&[u8]>, start_pos: (i32, i32), steps: i32) -> u64 {
if steps < 0 {
return 0;
}
let modulo_equal = steps % 2;
// Assuming square
let chunk_width = layout.len() as i32;
let chunk_reach = (steps + chunk_width / 2) / chunk_width + 1;
#[derive(Clone)]
struct Chunk {
visited: Vec<Vec<bool>>,
solution: i32,
}
impl Chunk {
fn new(width: usize, height: usize) -> Chunk {
Chunk {
visited: vec![vec![false; width]; height],
solution: 0,
}
}
}
let chunk_offset = chunk_reach - 1;
let chunks_size = chunk_reach * 2 - 1;
let mut chunks: Vec<Vec<Chunk>> = vec![vec![Chunk::new(chunk_width as usize, chunk_width as usize); chunks_size as usize]; chunks_size as usize];
let mut tile_queue: Vec<(i32, i32)> = vec![start_pos];
let mut sum = 0;
let mut next_tile_queue: Vec<(i32, i32)> = vec![];
for step in 1..=steps {
let mut try_tile = |x: i32, y: i32| {
let mut chunk_x = if x < 0 { (x - chunk_width + 1) / chunk_width } else { x / chunk_width };
let mut chunk_y = if y < 0 { (y - chunk_width + 1) / chunk_width } else { y / chunk_width };
let inside_x = (x - chunk_x * chunk_width) as usize;
let inside_y = (y - chunk_y * chunk_width) as usize;
chunk_x += chunk_offset;
chunk_y += chunk_offset;
if chunk_x < 0 || chunk_y < 0 || chunk_x >= chunks_size || chunk_y >= chunks_size {
// println!("Out of bounds");
return;
}
let chunk = &mut chunks[chunk_y as usize][chunk_x as usize];
if layout[inside_y][inside_x] != b'#' {
if !chunk.visited[inside_y][inside_x] {
chunk.visited[inside_y][inside_x] = true;
next_tile_queue.push((x, y));
if step % 2 == modulo_equal {
sum += 1;
chunk.solution += 1;
}
}
}
};
for &(x, y) in &tile_queue {
try_tile(x - 1, y);
try_tile(x + 1, y);
try_tile(x, y - 1);
try_tile(x, y + 1);
}
tile_queue.clear();
mem::swap(&mut tile_queue, &mut next_tile_queue);
}
// for row in &chunks {
// println!("{:?}", row.iter().map(|chunk| chunk.solution).collect::<Vec<_>>());
// }
sum
}
// Solution to part 2, makes an assumption that the starting row and column are empty
fn count_options_infinite(layout: &Vec<&[u8]>, steps: i32) -> u64 {
// Assuming square
let chunk_width = layout.len() as i32;
// Assuming the start is in the middle of chunk (it is so in the input)
let start_pos = chunk_width / 2;
// How many chunks in line from the start would the search reach
let chunk_reach = (steps + chunk_width / 2) / chunk_width + 1;
let chunk_reach_diag = (steps - 1) / chunk_width + 1;
// Used to get solutions for various kinds of edge garden repetitions of the reachable region
let count_options_adjusted = |start_pos: (i32, i32), steps_to_edge: i32| {
let remaining_steps = steps - steps_to_edge;
count_options_basic(layout, start_pos, remaining_steps)
};
// Order: N, W, S, E
let edges_straight_closer = [
count_options_adjusted(
(start_pos, chunk_width - 1),
start_pos + 1 + (chunk_reach - 3) * chunk_width),
count_options_adjusted(
(0, start_pos),
start_pos + 1 + (chunk_reach - 3) * chunk_width),
count_options_adjusted(
(start_pos, 0),
start_pos + 1 + (chunk_reach - 3) * chunk_width),
count_options_adjusted(
(chunk_width - 1, start_pos),
start_pos + 1 + (chunk_reach - 3) * chunk_width)
];
let edges_straight_further = [
count_options_adjusted(
(start_pos, chunk_width - 1),
start_pos + 1 + (chunk_reach - 2) * chunk_width),
count_options_adjusted(
(0, start_pos),
start_pos + 1 + (chunk_reach - 2) * chunk_width),
count_options_adjusted(
(start_pos, 0),
start_pos + 1 + (chunk_reach - 2) * chunk_width),
count_options_adjusted(
(chunk_width - 1, start_pos),
start_pos + 1 + (chunk_reach - 2) * chunk_width)
];
// Order: NE, NW, SW, SE
let edges_diagonal_closer = [
count_options_adjusted(
(chunk_width - 1, chunk_width - 1),
2 * (start_pos + 1) + (chunk_reach_diag - 3) * chunk_width),
count_options_adjusted(
(0, chunk_width - 1),
2 * (start_pos + 1) + (chunk_reach_diag - 3) * chunk_width),
count_options_adjusted(
(0, 0),
2 * (start_pos + 1) + (chunk_reach_diag - 3) * chunk_width),
count_options_adjusted(
(chunk_width - 1, 0),
2 * (start_pos + 1) + (chunk_reach_diag - 3) * chunk_width)
];
let edges_diagonal_further = [
count_options_adjusted(
(chunk_width - 1, chunk_width - 1),
2 * (start_pos + 1) + (chunk_reach_diag - 2) * chunk_width),
count_options_adjusted(
(0, chunk_width - 1),
2 * (start_pos + 1) + (chunk_reach_diag - 2) * chunk_width),
count_options_adjusted(
(0, 0),
2 * (start_pos + 1) + (chunk_reach_diag - 2) * chunk_width),
count_options_adjusted(
(chunk_width - 1, 0),
2 * (start_pos + 1) + (chunk_reach_diag - 2) * chunk_width)
];
let mut sum: u64 = 0;
if chunk_reach_diag < 3 {
// If the reach is small, compute the central chunk
sum += count_options_basic(layout, (start_pos, start_pos), steps);
}
if chunk_reach >= 2 {
// Fill the corners (of the rotated square)
sum += edges_straight_further.iter().sum::<u64>();
}
if chunk_reach_diag >= 2 {
// Fill the outer edges
sum += edges_diagonal_further.iter().sum::<u64>() * (chunk_reach_diag - 1) as u64;
}
if chunk_reach >= 3 {
// Fill the inner corners (of the rotated square)
sum += edges_straight_closer.iter().sum::<u64>();
}
if chunk_reach_diag >= 3 {
// Fill the space where we know chunks will be fully filled
let full_even = count_options_basic_cont(
layout, (start_pos, start_pos), 2 * chunk_width, false);
let full_odd = count_options_basic_cont(
layout, (start_pos, start_pos), 2 * chunk_width, true);
let r = chunk_reach_diag as u64;
let quadratic1 = r * r + 4 - 4 * r;
let quadratic2 = r * r - 2 * r - 3;
if (chunk_reach_diag + steps) % 2 == 0 {
sum += full_even * quadratic2;
sum += full_odd * quadratic1;
} else {
sum += full_even * quadratic1;
sum += full_odd * quadratic2;
}
// Fill the inner edges
sum += edges_diagonal_closer.iter().sum::<u64>() * (chunk_reach_diag - 2) as u64;
// Fill the extension of central shape if the corners stick out more
if chunk_reach > chunk_reach_diag {
sum += 4 * if chunk_reach_diag % 2 == 0 { full_even } else {full_odd};
}
}
sum
}
fn main() {
let time_start = Instant::now();
let input_str = read_to_string("input.txt").unwrap();
let time_start_no_io = Instant::now();
let mut start_pos: (i32, i32) = (0, 0);
let mut layout: Vec<&[u8]> = vec![];
for line in input_str.lines() {
let bytes = line.as_bytes();
match bytes.iter().position(|&c| c == b'S') {
Some(pos) => {
start_pos = (pos as i32, layout.len() as i32);
}
None => {}
}
layout.push(bytes);
}
// Part 1
let sum1 = count_options_basic(&layout, start_pos, 64);
// part 2
// let sum2 = count_options_infinite_naive(&layout, start_pos, 500);
let sum2 = count_options_infinite(&layout, 26501365);
let elapsed = time_start.elapsed().as_micros();
let elapsed_no_io = time_start_no_io.elapsed().as_micros();
println!("Time: {}us", elapsed);
println!("Time without file i/o: {}us", elapsed_no_io);
println!("Sum1: {}", sum1);
println!("Sum2: {}", sum2);
}