Day 17, part 2
This commit is contained in:
parent
1e7eb12da9
commit
22d9f7c42a
13
src/bin/d17p2.rs
Normal file
13
src/bin/d17p2.rs
Normal 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)
|
||||||
|
);
|
||||||
|
}
|
75
src/day17.rs
75
src/day17.rs
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
@ -148,14 +150,45 @@ impl Block {
|
|||||||
|
|
||||||
type VentRow = u8;
|
type VentRow = u8;
|
||||||
|
|
||||||
|
const CYCLE_SIZE: usize = 5;
|
||||||
|
|
||||||
pub fn do_moves(jets: &Vec<Jet>, n_blocks: usize) -> usize {
|
pub fn do_moves(jets: &Vec<Jet>, n_blocks: usize) -> usize {
|
||||||
let mut block_i = 0;
|
let mut block_i = 0;
|
||||||
let mut current_block: Option<Block> = None;
|
let mut current_block: Option<Block> = None;
|
||||||
let mut vent = vec![0; 4];
|
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;
|
let mut round = 0;
|
||||||
while block_i <= n_blocks {
|
while block_i <= n_blocks {
|
||||||
|
let jet_i = round % jets.len();
|
||||||
|
|
||||||
if current_block.is_none() {
|
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));
|
current_block = Some(spawn_block(&mut vent, block_i % N_BLOCK_TYPES));
|
||||||
// println!("Vent as block {} begins falling:", block_i);
|
// println!("Vent as block {} begins falling:", block_i);
|
||||||
// print_vent(&vent, current_block.as_ref());
|
// 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();
|
let block = current_block.as_mut().unwrap();
|
||||||
|
|
||||||
// Push left/right
|
// Push left/right
|
||||||
let jet = jets[round % jets.len()];
|
let jet = jets[jet_i];
|
||||||
if block.can_push(&vent, jet) {
|
if block.can_push(&vent, jet) {
|
||||||
let (_, ref mut col) = block.pos;
|
let (_, ref mut col) = block.pos;
|
||||||
*col = ((*col as isize) - jet.shift()) as usize;
|
*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;
|
round += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vent.len() - empty_rows(&vent)
|
vent.len() - empty_rows(&vent) + skipped_height.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SPAWN_OFFSET_X: usize = 2;
|
const SPAWN_OFFSET_X: usize = 2;
|
||||||
@ -244,3 +277,41 @@ pub fn print_vent(vent: &Vec<VentRow>, block: Option<&Block>) {
|
|||||||
}
|
}
|
||||||
println!("+-------+");
|
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user