summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2022-12-20 11:37:32 +0100
committerReiner Herrmann <reiner@reiner-h.de>2022-12-20 11:37:32 +0100
commit7c4319128f8d3702e58ace9965a00f87a3812b41 (patch)
treee2d8305a8429e270d7496869775786ec6ed8ace7 /src/bin
parentae010a5efd7bdc4cf7902e791ef9e0c769e1cd92 (diff)
day17 part1
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/day17.rs257
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);
+ }
+}