This commit is contained in:
Acvaxoort
2023-12-14 16:37:36 +01:00
parent e3d4b31f88
commit 34c7808394
4 changed files with 305 additions and 0 deletions

190
day14/src/main.rs Normal file
View File

@@ -0,0 +1,190 @@
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::fs::read_to_string;
use std::hash::Hash;
use std::time::Instant;
// For task 1
fn slide_rock_north(platform: &mut Vec<Vec<u8>>, col: usize, row: usize) -> i32 {
let mut steps = 0;
let mut current_row = row;
while current_row > 0 {
let new_row = current_row - 1;
if platform[new_row][col] != b'.' {
break;
}
platform[new_row][col] = b'O';
platform[current_row][col] = b'.';
steps += 1;
current_row = new_row
}
steps
}
// Slides all rocks on platform north, returns change of load
fn slide_platform_north(platform: &mut Vec<Vec<u8>>) -> i32 {
let rows = platform.len();
let cols = platform[0].len();
let mut load_change = 0;
for row in 1..rows {
for col in 0..cols {
if platform[row][col] != b'O' {
continue;
}
let mut sliding_row = row;
while sliding_row > 0 {
let new_row = sliding_row - 1;
if platform[new_row][col] != b'.' {
break;
}
load_change += 1;
platform[new_row][col] = b'O';
platform[sliding_row][col] = b'.';
sliding_row = new_row
}
}
}
load_change
}
// Slides all rocks on platform south, returns change of load
fn slide_platform_south(platform: &mut Vec<Vec<u8>>) -> i32 {
let rows = platform.len();
let cols = platform[0].len();
let mut load_change = 0;
for row in (0..rows - 1).rev() {
for col in 0..cols {
if platform[row][col] != b'O' {
continue;
}
let mut sliding_row = row;
while sliding_row < rows - 1 {
let new_row = sliding_row + 1;
if platform[new_row][col] != b'.' {
break;
}
load_change -= 1;
platform[new_row][col] = b'O';
platform[sliding_row][col] = b'.';
sliding_row = new_row
}
}
}
load_change
}
// Slides all rocks on platform west, there's no change in load
fn slide_platform_west(platform: &mut Vec<Vec<u8>>) {
let rows = platform.len();
let cols = platform[0].len();
for row in 0..rows {
for col in 1..cols {
if platform[row][col] != b'O' {
continue;
}
let mut sliding_col = col;
while sliding_col > 0 {
let new_col = sliding_col - 1;
if platform[row][new_col] != b'.' {
break;
}
platform[row][new_col] = b'O';
platform[row][sliding_col] = b'.';
sliding_col = new_col
}
}
}
}
// Slides all rocks on platform east, there's no change in load
fn slide_platform_east(platform: &mut Vec<Vec<u8>>) {
let rows = platform.len();
let cols = platform[0].len();
for row in 0..rows {
for col in (0..cols - 1).rev() {
if platform[row][col] != b'O' {
continue;
}
let mut sliding_col = col;
while sliding_col < cols - 1 {
let new_col = sliding_col + 1;
if platform[row][new_col] != b'.' {
break;
}
platform[row][new_col] = b'O';
platform[row][sliding_col] = b'.';
sliding_col = new_col
}
}
}
}
fn hash_platform(platform: &Vec<Vec<u8>>) -> u64 {
let mut hasher = DefaultHasher::new();
platform.hash(&mut hasher);
hasher.finish()
}
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 platform: Vec<Vec<u8>> = vec![];
let mut sum1 = 0;
let mut num_rocks = 0;
// Solve task 1 while loading the data
for line in input_str.lines() {
platform.push(Vec::from(line.as_bytes()));
sum1 += num_rocks;
let last_row = platform.len() - 1;
for (i, c) in line.bytes().enumerate() {
if c == b'O' {
num_rocks += 1;
sum1 += 1 + slide_rock_north(&mut platform, i, last_row);
}
}
}
// Task 2
let mut load = sum1;
// Complete the first cycle
slide_platform_west(&mut platform);
load += slide_platform_south(&mut platform);
slide_platform_east(&mut platform);
let mut history_hashes: Vec::<u64> = vec![hash_platform(&platform)];
let mut history_loads: Vec::<i32> = vec![load];
let mut completed_cycles = 1;
let mut len_repeat_cycle = 0;
while completed_cycles < 1000000000 {
load += slide_platform_north(&mut platform);
slide_platform_west(&mut platform);
load += slide_platform_south(&mut platform);
slide_platform_east(&mut platform);
// Check if this value happened before
let mut history_pos = completed_cycles - 1;
let new_hash = hash_platform(&platform);
loop {
if history_hashes[history_pos] == new_hash {
len_repeat_cycle = completed_cycles - history_pos;
}
if history_pos == 0 {
break;
}
history_pos -= 1;
}
completed_cycles += 1;
history_hashes.push(new_hash);
history_loads.push(load);
if len_repeat_cycle != 0 {
break;
}
}
const FINAL_CYCLE: usize = 1000000000;
let offset_final = (FINAL_CYCLE - completed_cycles) % len_repeat_cycle;
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!("Load after first tilt: {}", sum1);
println!("Completed cycles: {}, repeat: {}", completed_cycles, len_repeat_cycle);
println!("Load after {} cycles: {}", FINAL_CYCLE, history_loads[completed_cycles - len_repeat_cycle - 1 + offset_final]);
}