Day 17, part 2

This commit is contained in:
jazzpi 2022-12-20 15:59:53 +01:00
parent 1e7eb12da9
commit 22d9f7c42a
2 changed files with 86 additions and 2 deletions

13
src/bin/d17p2.rs Normal file
View File

@ -0,0 +1,13 @@
use aoc22::{day17, util};
const BLOCKS: usize = 1_000_000_000_000;
pub fn main() {
let jets = day17::parse_jets(&util::parse_input());
println!(
"Height after {} blocks: {}",
BLOCKS,
day17::do_moves(&jets, BLOCKS)
);
}

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use once_cell::sync::OnceCell;
use crate::util;
@ -148,14 +150,45 @@ impl Block {
type VentRow = u8;
const CYCLE_SIZE: usize = 5;
pub fn do_moves(jets: &Vec<Jet>, n_blocks: usize) -> usize {
let mut block_i = 0;
let mut current_block: Option<Block> = None;
let mut vent = vec![0; 4];
// {jet_i: {round: (height, block_i)}}
let mut block_cycles: HashMap<usize, HashMap<usize, (usize, usize)>> = HashMap::new();
let mut skipped_height: Option<usize> = None;
let mut round = 0;
while block_i <= n_blocks {
let jet_i = round % jets.len();
if current_block.is_none() {
if block_i % N_BLOCK_TYPES == 0 {
if skipped_height.is_none() {
let entry = block_cycles.entry(jet_i).or_insert_with(HashMap::new);
entry.insert(round, (vent.len() - empty_rows(&vent), block_i));
if let Some((cycle_height, cycle_blocks)) = find_cycle(entry, CYCLE_SIZE) {
println!(
"Found cycle ({} height per {} blocks) after {} rounds!",
cycle_height, cycle_blocks, round
);
let remaining_blocks = n_blocks - block_i;
let cycles = remaining_blocks / cycle_blocks;
block_i += cycles * cycle_blocks;
skipped_height = Some(cycles * cycle_height);
println!(
"Skipping {} blocks, {} height",
cycles * cycle_blocks,
cycles * cycle_height
);
}
}
}
current_block = Some(spawn_block(&mut vent, block_i % N_BLOCK_TYPES));
// println!("Vent as block {} begins falling:", block_i);
// print_vent(&vent, current_block.as_ref());
@ -165,7 +198,7 @@ pub fn do_moves(jets: &Vec<Jet>, n_blocks: usize) -> usize {
let block = current_block.as_mut().unwrap();
// Push left/right
let jet = jets[round % jets.len()];
let jet = jets[jet_i];
if block.can_push(&vent, jet) {
let (_, ref mut col) = block.pos;
*col = ((*col as isize) - jet.shift()) as usize;
@ -182,7 +215,7 @@ pub fn do_moves(jets: &Vec<Jet>, n_blocks: usize) -> usize {
round += 1;
}
vent.len() - empty_rows(&vent)
vent.len() - empty_rows(&vent) + skipped_height.unwrap_or(0)
}
const SPAWN_OFFSET_X: usize = 2;
@ -244,3 +277,41 @@ pub fn print_vent(vent: &Vec<VentRow>, block: Option<&Block>) {
}
println!("+-------+");
}
fn find_cycle(
jet_heights: &HashMap<usize, (usize, usize)>,
n_cycles: usize,
) -> Option<(usize, usize)> {
if jet_heights.len() < n_cycles {
return None;
}
for (init_round, (init_height, init_blocks)) in jet_heights {
'next_loop: for (next_round, (next_height, next_blocks)) in jet_heights {
if init_round == next_round || *next_height < *init_height {
continue;
}
let cycle = next_round - init_round;
let cycle_height = next_height - init_height;
let cycle_blocks = next_blocks - init_blocks;
for n in 2..=n_cycles {
let round = init_round + n * cycle;
let entry = jet_heights.get(&round);
if let Some((height, blocks)) = entry {
let expected_height = init_height + n * cycle_height;
let expected_blocks = init_blocks + n * cycle_blocks;
if *height != expected_height || *blocks != expected_blocks {
continue 'next_loop;
}
} else {
continue 'next_loop;
}
}
return Some((cycle_height, cycle_blocks));
}
}
None
}