advent-of-code/2022/src/day_17.rs
2022-12-28 23:25:32 -05:00

259 lines
8.4 KiB
Rust

type Board = Vec<[bool; 7]>;
#[derive(Clone, Copy, Debug)]
enum BlockType {
Square,
L,
Horizontal,
Vertical,
Cross,
}
impl BlockType {
fn height(&self) -> usize {
match *self {
Square => 2,
L => 3,
Horizontal => 1,
Vertical => 4,
Cross => 3,
}
}
}
use BlockType::*;
#[derive(Debug)]
struct Position {
row: usize,
col: usize,
}
#[derive(Debug)]
struct Block {
pos: Position,
block_type: BlockType,
}
impl Block {
fn left(&mut self, board: &Board) {
let cond = match self.block_type {
Square => {
self.pos.col > 0
&& !board[self.pos.row][self.pos.col - 1]
&& !board[self.pos.row - 1][self.pos.col - 1]
}
L => {
self.pos.col > 0
&& !board[self.pos.row][self.pos.col + 1]
&& !board[self.pos.row - 1][self.pos.col + 1]
&& !board[self.pos.row - 2][self.pos.col - 1]
}
Cross => {
self.pos.col > 0
&& !board[self.pos.row][self.pos.col]
&& !board[self.pos.row - 1][self.pos.col - 1]
&& !board[self.pos.row - 2][self.pos.col]
}
Horizontal => self.pos.col > 0 && !board[self.pos.row][self.pos.col - 1],
Vertical => {
self.pos.col > 0
&& !board[self.pos.row][self.pos.col - 1]
&& !board[self.pos.row - 1][self.pos.col - 1]
&& !board[self.pos.row - 2][self.pos.col - 1]
&& !board[self.pos.row - 3][self.pos.col - 1]
}
};
if cond {
self.pos.col -= 1;
}
println!("left to {:?}, {:?}", self.pos, self.block_type);
}
fn right(&mut self, board: &Board) {
let cond = match self.block_type {
Square => {
self.pos.col < 5
&& !board[self.pos.row][self.pos.col + 2]
&& !board[self.pos.row - 1][self.pos.col + 2]
}
L => {
self.pos.col < 4
&& !board[self.pos.row][self.pos.col + 3]
&& !board[self.pos.row - 1][self.pos.col + 3]
&& !board[self.pos.row - 2][self.pos.col + 3]
}
Cross => {
self.pos.col < 4
&& !board[self.pos.row][self.pos.col + 2]
&& !board[self.pos.row - 1][self.pos.col + 3]
&& !board[self.pos.row - 2][self.pos.col + 2]
}
Horizontal => self.pos.col < 3 && !board[self.pos.row][self.pos.col + 4],
Vertical => {
self.pos.col < 6
&& !board[self.pos.row][self.pos.col + 1]
&& !board[self.pos.row - 1][self.pos.col + 1]
&& !board[self.pos.row - 2][self.pos.col + 1]
&& !board[self.pos.row - 3][self.pos.col + 1]
}
};
if cond {
self.pos.col += 1;
}
println!("right to {:?}, {:?}", self.pos, self.block_type);
}
/// Returns if the block comes to rest (and can't move down)
/// board will only be mutated to insert the object if the block is at rest
fn down(&mut self, board: &mut Board) -> bool {
let is_falling = match self.block_type {
Square => {
self.pos.row > 1
&& !board[self.pos.row - 2][self.pos.col]
&& !board[self.pos.row - 2][self.pos.col + 1]
}
L => {
self.pos.row > 2
&& !board[self.pos.row - 3][self.pos.col]
&& !board[self.pos.row - 3][self.pos.col + 1]
&& !board[self.pos.row - 3][self.pos.col + 2]
}
Cross => {
self.pos.row > 2
&& !board[self.pos.row - 2][self.pos.col]
&& !board[self.pos.row - 3][self.pos.col + 1]
&& !board[self.pos.row - 2][self.pos.col + 2]
}
Horizontal => {
self.pos.row > 0
&& !board[self.pos.row - 1][self.pos.col]
&& !board[self.pos.row - 1][self.pos.col + 1]
&& !board[self.pos.row - 1][self.pos.col + 2]
&& !board[self.pos.row - 1][self.pos.col + 3]
}
Vertical => self.pos.row > 3 && !board[self.pos.row - 4][self.pos.col],
};
if is_falling {
self.pos.row -= 1;
}
println!(
"down to {:?}, is falling? {:?}, {:?}",
self.pos, is_falling, self.block_type
);
!is_falling
}
fn draw(&self, board: &mut Board) {
match self.block_type {
Square => {
board[self.pos.row][self.pos.col] = true;
board[self.pos.row][self.pos.col + 1] = true;
board[self.pos.row - 1][self.pos.col] = true;
board[self.pos.row - 1][self.pos.col + 1] = true;
}
L => {
board[self.pos.row][self.pos.col + 2] = true;
board[self.pos.row - 1][self.pos.col + 2] = true;
board[self.pos.row - 2][self.pos.col + 2] = true;
board[self.pos.row - 2][self.pos.col + 1] = true;
board[self.pos.row - 2][self.pos.col] = true;
}
Cross => {
board[self.pos.row][self.pos.col + 1] = true;
board[self.pos.row - 1][self.pos.col + 1] = true;
board[self.pos.row - 2][self.pos.col + 1] = true;
board[self.pos.row - 1][self.pos.col] = true;
board[self.pos.row - 1][self.pos.col + 2] = true;
}
Horizontal => {
board[self.pos.row][self.pos.col] = true;
board[self.pos.row][self.pos.col + 1] = true;
board[self.pos.row][self.pos.col + 2] = true;
board[self.pos.row][self.pos.col + 3] = true;
}
Vertical => {
board[self.pos.row][self.pos.col] = true;
board[self.pos.row - 1][self.pos.col] = true;
board[self.pos.row - 2][self.pos.col] = true;
board[self.pos.row - 3][self.pos.col] = true;
}
}
}
}
type Data = &'static str;
type Output = i32;
fn parse(input: &'static str) -> Data {
input
}
fn part_one(data: Data) -> Output {
let mut blocks = vec![Horizontal, Cross, L, Vertical, Square]
.into_iter()
.cycle();
let mut top = -1i32;
let block_type = blocks.next().unwrap();
let mut curr = Block {
pos: Position { row: 3, col: 2 },
block_type,
};
let mut board = vec![[false; 7]; 5];
let mut num_rocks = 0;
for c in data.chars().cycle() {
match c {
'>' => curr.right(&board),
'<' => curr.left(&board),
_ => {}
}
if curr.down(&mut board) {
curr.draw(&mut board);
top = board
.iter()
.enumerate()
.rev()
.find(|(_, el)| **el != [false; 7])
.map(|(idx, _)| idx as i32)
.unwrap();
num_rocks += 1;
println!();
for line in board.iter().rev() {
print!("|");
line.iter()
.map(|filled| if *filled { '#' } else { '.' })
.for_each(|c| print!("{c}"));
println!("|");
}
println!("+-------+");
println!("{:?}", top);
println!();
if num_rocks == 15 {
return top;
}
let block_type = blocks.next().unwrap();
let start_row = top + 3 + block_type.height() as i32;
while board.len() <= start_row as usize {
board.push([false; 7]);
}
curr = Block {
pos: Position {
row: start_row as usize,
col: 2,
},
block_type,
};
}
}
unreachable!()
}
fn part_two(_data: Data) -> Output {
todo!()
}
advent_of_code_macro::generate_tests!(
day 17,
parse,
part_one,
part_two,
sample tests [3068, 0],
star tests [0, 0]
);