Day 17, part 1
This commit is contained in:
parent
06786817f3
commit
1e7eb12da9
|
@ -20,6 +20,7 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"log",
|
||||
"num",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
|
@ -250,6 +251,12 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
|
|
|
@ -12,6 +12,7 @@ log = "^0.4"
|
|||
env_logger = "^0.10"
|
||||
num = "^0.1"
|
||||
lazy_static = "^1.4"
|
||||
once_cell = "^1.16"
|
||||
|
||||
[[bin]]
|
||||
name = "d1p1"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
use aoc22::{day17, util};
|
||||
|
||||
const BLOCKS: usize = 2022;
|
||||
|
||||
pub fn main() {
|
||||
let jets = day17::parse_jets(&util::parse_input());
|
||||
|
||||
println!(
|
||||
"Height after {} blocks: {}",
|
||||
BLOCKS,
|
||||
day17::do_moves(&jets, BLOCKS)
|
||||
);
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::util;
|
||||
|
||||
const VENT_WIDTH: usize = 7;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Jet {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Jet {
|
||||
pub fn shift(&self) -> isize {
|
||||
match &self {
|
||||
Jet::Left => 1,
|
||||
Jet::Right => -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_jets(input: &String) -> Vec<Jet> {
|
||||
assert_eq!(input.lines().count(), 1);
|
||||
input
|
||||
.chars()
|
||||
.filter_map(|c| match c {
|
||||
'<' => Some(Jet::Left),
|
||||
'>' => Some(Jet::Right),
|
||||
'\n' => None,
|
||||
_ => panic!("Unknown jet {}", c),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum BlockKind {
|
||||
Dash = 0,
|
||||
Plus,
|
||||
L,
|
||||
Pipe,
|
||||
Square,
|
||||
}
|
||||
|
||||
impl BlockKind {
|
||||
pub fn from_num(n: usize) -> BlockKind {
|
||||
match n {
|
||||
0 => BlockKind::Dash,
|
||||
1 => BlockKind::Plus,
|
||||
2 => BlockKind::L,
|
||||
3 => BlockKind::Pipe,
|
||||
4 => BlockKind::Square,
|
||||
_ => panic!("Unknown block kind {}", n),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
match self {
|
||||
BlockKind::Dash => 1,
|
||||
BlockKind::Plus => 3,
|
||||
BlockKind::L => 3,
|
||||
BlockKind::Pipe => 4,
|
||||
BlockKind::Square => 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
match self {
|
||||
BlockKind::Dash => 4,
|
||||
BlockKind::Plus => 3,
|
||||
BlockKind::L => 3,
|
||||
BlockKind::Pipe => 1,
|
||||
BlockKind::Square => 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vent_rows(&self) -> &'static Vec<VentRow> {
|
||||
static ROWS: OnceCell<Vec<Vec<VentRow>>> = OnceCell::new();
|
||||
let rows = ROWS.get_or_init(|| {
|
||||
vec![
|
||||
vec![0b1111], // Dash
|
||||
vec![0b010, 0b111, 0b010], // Plus
|
||||
vec![0b001, 0b001, 0b111], // L
|
||||
vec![0b1; 4], // Pipe
|
||||
vec![0b11, 0b11], // Square
|
||||
]
|
||||
});
|
||||
&rows
|
||||
.get(*self as usize)
|
||||
.unwrap_or_else(|| panic!("Unknown BlockKind: {:?}", self))
|
||||
}
|
||||
}
|
||||
|
||||
const N_BLOCK_TYPES: usize = 5;
|
||||
|
||||
pub struct Block {
|
||||
kind: BlockKind,
|
||||
pos: util::Coord,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn spawn(&self, vent: &mut Vec<VentRow>) {
|
||||
for (i, row) in self.kind.vent_rows().iter().rev().enumerate() {
|
||||
vent[self.pos.0 + i] |= *row << self.shift_dist();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn row_range(&self) -> std::ops::Range<usize> {
|
||||
let row = self.pos.0;
|
||||
row..(row + self.kind.height())
|
||||
}
|
||||
|
||||
pub fn can_push(&self, vent: &Vec<VentRow>, jet: Jet) -> bool {
|
||||
if (jet == Jet::Left && self.pos.1 == 0)
|
||||
|| (jet == Jet::Right && self.pos.1 + self.kind.width() >= VENT_WIDTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let shift = self.shift_dist() as isize + jet.shift();
|
||||
for (i, row) in self.row_range().rev().enumerate() {
|
||||
let bitmask = self.kind.vent_rows()[i] << shift;
|
||||
if vent[row] & bitmask != 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn can_fall(&self, vent: &Vec<VentRow>) -> bool {
|
||||
if self.pos.0 == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i, row) in self.row_range().rev().enumerate() {
|
||||
let bitmask = self.kind.vent_rows()[i] << self.shift_dist();
|
||||
if vent[row - 1] & bitmask != 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn shift_dist(&self) -> usize {
|
||||
VENT_WIDTH - self.pos.1 - self.kind.width()
|
||||
}
|
||||
}
|
||||
|
||||
type VentRow = u8;
|
||||
|
||||
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];
|
||||
|
||||
let mut round = 0;
|
||||
while block_i <= n_blocks {
|
||||
if current_block.is_none() {
|
||||
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());
|
||||
// println!("");
|
||||
block_i += 1;
|
||||
}
|
||||
let block = current_block.as_mut().unwrap();
|
||||
|
||||
// Push left/right
|
||||
let jet = jets[round % jets.len()];
|
||||
if block.can_push(&vent, jet) {
|
||||
let (_, ref mut col) = block.pos;
|
||||
*col = ((*col as isize) - jet.shift()) as usize;
|
||||
}
|
||||
|
||||
// Fall
|
||||
if block.can_fall(&vent) {
|
||||
let (ref mut row, _) = block.pos;
|
||||
*row -= 1;
|
||||
} else {
|
||||
block.spawn(&mut vent);
|
||||
current_block = None;
|
||||
}
|
||||
round += 1;
|
||||
}
|
||||
|
||||
vent.len() - empty_rows(&vent)
|
||||
}
|
||||
|
||||
const SPAWN_OFFSET_X: usize = 2;
|
||||
const SPAWN_OFFSET_Y: usize = 3;
|
||||
|
||||
fn spawn_block(vent: &mut Vec<VentRow>, block: usize) -> Block {
|
||||
let block = BlockKind::from_num(block);
|
||||
|
||||
let mut empty_rows = empty_rows(vent);
|
||||
let diff = (block.height() as isize + 3) - (empty_rows as isize);
|
||||
if diff > 0 {
|
||||
vent.append(&mut vec![0; diff as usize]);
|
||||
empty_rows += diff as usize;
|
||||
}
|
||||
|
||||
let row = vent.len() - empty_rows + SPAWN_OFFSET_Y;
|
||||
let col = SPAWN_OFFSET_X;
|
||||
|
||||
assert!(row + block.height() - 1 < vent.len());
|
||||
|
||||
let block = Block {
|
||||
kind: block,
|
||||
pos: (row, col),
|
||||
};
|
||||
|
||||
block
|
||||
}
|
||||
|
||||
fn empty_rows(vent: &Vec<VentRow>) -> usize {
|
||||
vent.iter()
|
||||
.rev()
|
||||
.position(|r| *r != 0)
|
||||
.unwrap_or_else(|| vent.len())
|
||||
}
|
||||
|
||||
pub fn print_vent(vent: &Vec<VentRow>, block: Option<&Block>) {
|
||||
let block_rows = block.map(|b| b.kind.vent_rows());
|
||||
let block_range = block.map(|b| b.row_range());
|
||||
let block_range = block_range.as_ref();
|
||||
for (r, vent_row) in vent.iter().enumerate().rev() {
|
||||
print!("|");
|
||||
let block_collision = if block.is_some() && block_range.unwrap().contains(&r) {
|
||||
block_rows.unwrap()[block_range.unwrap().end - r - 1] << block.unwrap().shift_dist()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
for i in (0..VENT_WIDTH).rev() {
|
||||
let col = 1 << i;
|
||||
let c = if (block_collision & col) != 0 {
|
||||
'@'
|
||||
} else if (vent_row & col) == 0 {
|
||||
'.'
|
||||
} else {
|
||||
'#'
|
||||
};
|
||||
print!("{}", c);
|
||||
}
|
||||
print!("|\n");
|
||||
}
|
||||
println!("+-------+");
|
||||
}
|
|
@ -6,6 +6,7 @@ pub mod day13;
|
|||
pub mod day14;
|
||||
pub mod day15;
|
||||
pub mod day16;
|
||||
pub mod day17;
|
||||
pub mod day2;
|
||||
pub mod day3;
|
||||
pub mod day4;
|
||||
|
|
Loading…
Reference in New Issue