diff options
Diffstat (limited to 'src/bin/day17.rs')
| -rw-r--r-- | src/bin/day17.rs | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/bin/day17.rs b/src/bin/day17.rs new file mode 100644 index 0000000..b262a9d --- /dev/null +++ b/src/bin/day17.rs @@ -0,0 +1,257 @@ +use std::collections::HashSet; + +static DAY: u8 = 17; + +fn main() { + let input = advent::read_lines(DAY); + println!("{DAY}a: {}", simulate_rocks(&input[0], 2022)); + println!("{DAY}b: {}", 0); +} + +#[derive(Debug)] +struct Shape { + shape: u8, + pos: (u64, u64), // top left position of the bounding box +} + +impl Shape { + fn next(&self, map: &HashSet<(u64,u64)>) -> Shape { + let next_shape = (self.shape + 1) % 5; + Shape::new(map, next_shape) + } + + fn new(map: &HashSet<(u64,u64)>, shape: u8) -> Shape { + let max_y = map.iter() + .map(|pos| pos.1 as i64) + .max() + .unwrap_or(-1); + + let new_y = max_y + 3 + match shape { + 0 => 1, + 1 => 3, + 2 => 3, + 3 => 4, + 4 => 2, + _ => unimplemented!(), + }; + Shape { + shape, + pos: (2, new_y as u64), + } + } + + fn can_move_down(&self, map: &HashSet<(u64, u64)>) -> bool { + let (x,y) = self.pos; + match self.shape { + 0 => y > 0 && + !map.contains(&(x, y-1)) && + !map.contains(&(x+1, y-1)) && + !map.contains(&(x+2, y-1)) && + !map.contains(&(x+3, y-1)), + 1 => y > 2 && + !map.contains(&(x, y-2)) && + !map.contains(&(x+1, y-3)) && + !map.contains(&(x+2, y-2)), + 2 => y > 2 && + !map.contains(&(x, y-3)) && + !map.contains(&(x+1, y-3)) && + !map.contains(&(x+2, y-3)), + 3 => y > 3 && + !map.contains(&(x, y-4)), + 4 => y > 1 && + !map.contains(&(x, y-2)) && + !map.contains(&(x+1, y-2)), + _ => unimplemented!(), + } + } + + fn can_move_left(&self, map: &HashSet<(u64, u64)>) -> bool { + let (x,y) = self.pos; + if x == 0 { + return false; + } + match self.shape { + 0 => !map.contains(&(x-1, y)), + 1 => !map.contains(&(x, y)) && + !map.contains(&(x-1, y-1)) && + !map.contains(&(x, y-2)), + 2 => !map.contains(&(x+1, y)) && + !map.contains(&(x+1, y-1)) && + !map.contains(&(x-1, y-2)), + 3 => !map.contains(&(x-1, y)) && + !map.contains(&(x-1, y-1)) && + !map.contains(&(x-1, y-2)) && + !map.contains(&(x-1, y-3)), + 4 => !map.contains(&(x-1, y)) && + !map.contains(&(x-1, y-1)), + _ => unimplemented!(), + } + } + + fn can_move_right(&self, map: &HashSet<(u64, u64)>) -> bool { + let (x,y) = self.pos; + match self.shape { + 0 => x < (7-4) && + !map.contains(&(x+4, y)), + 1 => x < (7-3) && + !map.contains(&(x+2, y)) && + !map.contains(&(x+3, y-1)) && + !map.contains(&(x+2, y-2)), + 2 => x < (7-3) && + !map.contains(&(x+3, y)) && + !map.contains(&(x+3, y-1)) && + !map.contains(&(x+3, y-2)), + 3 => x < (7-1) && + !map.contains(&(x+1, y)) && + !map.contains(&(x+1, y-1)) && + !map.contains(&(x+1, y-2)) && + !map.contains(&(x+1, y-3)), + 4 => x < (7-2) && + !map.contains(&(x+2, y)) && + !map.contains(&(x+2, y-1)), + _ => unimplemented!(), + } + } + + fn move_left(&mut self, map: &HashSet<(u64, u64)>) { + if self.can_move_left(map) { + self.pos.0 -= 1; + } + } + + fn move_right(&mut self, map: &HashSet<(u64, u64)>) { + if self.can_move_right(map) { + self.pos.0 += 1; + } + } + + fn move_down(&mut self) { + self.pos.1 -= 1; + } + + fn movement(&mut self, map: &HashSet<(u64, u64)>, direction: char) { + match direction { + '>' => self.move_right(map), + '<' => self.move_left(map), + _ => unimplemented!(), + } + } + + fn add_to_map(&self, map: &mut HashSet<(u64, u64)>) { + let (x, y) = self.pos; + match self.shape { + 0 => { + map.insert((x, y)); + map.insert((x+1, y)); + map.insert((x+2, y)); + map.insert((x+3, y)); + }, + 1 => { + map.insert((x+1, y)); + map.insert((x, y-1)); + map.insert((x+1, y-1)); + map.insert((x+2, y-1)); + map.insert((x+1, y-2)); + }, + 2 => { + map.insert((x+2, y)); + map.insert((x+2, y-1)); + map.insert((x+2, y-2)); + map.insert((x+1, y-2)); + map.insert((x, y-2)); + }, + 3 => { + map.insert((x, y)); + map.insert((x, y-1)); + map.insert((x, y-2)); + map.insert((x, y-3)); + }, + 4 => { + map.insert((x, y)); + map.insert((x+1, y)); + map.insert((x, y-1)); + map.insert((x+1, y-1)); + } + _ => unimplemented!(), + } + } +} + +struct Tetris { + map: HashSet<(u64,u64)>, // positions occupied by rocks + rock: Shape, + count: u64, +} + +impl Tetris { + fn new() -> Tetris { + let map = HashSet::new(); + let rock = Shape::new(&map, 0); + Tetris { + map, + rock, + count: 0, + } + } + + fn step(&mut self, direction: char) { + self.rock.movement(&self.map, direction); + if self.rock.can_move_down(&self.map) { + self.rock.move_down(); + } else { + self.rock.add_to_map(&mut self.map); + self.rock = self.rock.next(&self.map); + self.count += 1; + } + } + + fn height(&self) -> u64 { + 1 + self.map.iter() + .map(|pos| pos.1) + .max() + .unwrap_or(0) + } + + fn dump_line(&self, y: u64) -> String { + let mut line = String::with_capacity(7); + for x in 0 .. 7 { + if self.map.contains(&(x, y as u64)) { + line.push('#'); + } else { + line.push('.'); + } + } + line + } + + fn dump_map(&self) { + for y in (0 ..= self.height()).rev() { + println!("|{}|", self.dump_line(y)); + } + println!("+-------+\n\n"); + } +} + +fn simulate_rocks(input: &str, max_rocks: u64) -> u64 { + let mut tetris = Tetris::new(); + for direction in input.chars().cycle() { + if tetris.count == max_rocks { + return tetris.height(); + } + tetris.step(direction); + } + + 0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let input = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>"; + + assert_eq!(simulate_rocks(&input, 2022), 3068); + } +} |
