Re: Advent of Code
Схоже, на цьому AoC для мене завершується...
▼2022#17.1, Rust
pub fn parse_input(input: &str) -> &str {
input.trim()
}
const TUBE_WIDTH: usize = 7;
#[rustfmt::skip]
const FIGURES: &[&[&[u8]]] = &[
&["####".as_bytes()],
&[".#.".as_bytes(),
"###".as_bytes(),
".#.".as_bytes()],
&["###".as_bytes(),
"..#".as_bytes(),
"..#".as_bytes()],
&["#".as_bytes(),
"#".as_bytes(),
"#".as_bytes(),
"#".as_bytes()],
&["##".as_bytes(),
"##".as_bytes()],
];
const EMPTY_LINE: &[u8] = ".......".as_bytes();
struct Tetris {
tube: Vec<Vec<u8>>,
figure: &'static [&'static [u8]],
x: i32,
y: i32,
count: usize,
}
impl Tetris {
fn new() -> Tetris {
Tetris {
tube: vec![EMPTY_LINE.to_vec(); 4],
figure: &FIGURES[0],
x: 2,
y: 3,
count: 0,
}
}
fn add_figure(&mut self) {
self.count += 1;
self.figure = &FIGURES[self.count % 5];
self.x = 2;
let free_lines = self.tube.len() - self.tower_height();
if free_lines < 3 + self.figure.len() {
self.tube.resize(
self.tube.len() + 3 + self.figure.len() - free_lines,
EMPTY_LINE.to_vec(),
);
}
self.y = (self.tower_height() + 3).try_into().unwrap();
}
fn move_figure(&mut self, dir: u8) {
let x = self.x
+ match dir {
b'>' => 1,
b'<' => -1,
_ => unimplemented!("Invalid move {}", dir),
};
if (0..=(TUBE_WIDTH - self.figure[0].len()) as i32).contains(&x)
&& self.fits(x as usize, self.y as usize)
{
self.x = x;
}
if self.y > 0 && self.fits(self.x as usize, (self.y - 1) as usize) {
self.y -= 1;
} else {
self.fix_figure();
self.add_figure();
}
}
fn fits(&self, x: usize, y: usize) -> bool {
self.figure.iter().enumerate().all(|(fy, fline)| {
fline.iter().enumerate().all(|(fx, &fchar)| {
fchar != b'#' || self.tube[y + fy][x + fx] != b'#'
})
})
}
fn fix_figure(&mut self) {
for f_y in 0..self.figure.len() {
for f_x in 0..self.figure[f_y].len() {
if self.figure[f_y][f_x] == b'#' {
self.tube[self.y as usize + f_y][self.x as usize + f_x] =
b'#';
}
}
}
}
fn tower_height(&self) -> usize {
self.tube.len()
- self
.tube
.iter()
.rev()
.take_while(|row| !row.contains(&b'#'))
.count()
}
fn play(&mut self, moves: &str, limit: usize) -> usize {
for &mov in moves.as_bytes().iter().cycle() {
self.move_figure(mov);
if self.count >= limit {
break;
}
}
self.tower_height()
}
fn print_top_n(&self, n: usize) {
println!("-----------------");
for i in 0..n.min(self.tube.len()) {
let line = std::str::from_utf8(&self.tube[self.tube.len() - 1 - i])
.unwrap();
println!("{}", line);
}
}
}
pub fn task1(input: &str) -> usize {
let mut tetris = Tetris::new();
tetris.play(&input, 2022)
}