Advertisement
Guest User

AoC 2022 Day 22

a guest
Dec 22nd, 2022
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 9.19 KB | Source Code | 0 0
  1. use grid::prelude::*;
  2. use std::{collections::HashMap, ops::Mul};
  3.  
  4. const N: i64 = 50;
  5.  
  6. pub fn part_1(input: &[String]) -> i64 {
  7.     let (board, path) = parse(input);
  8.     let mut pos = ZERO;
  9.     while board[pos] != MaybeTile::Open {
  10.         pos += EAST;
  11.     }
  12.     let mut facing = EAST;
  13.     for movement in path {
  14.         match movement {
  15.             Movement::Left => facing = -facing.perp(),
  16.             Movement::Right => facing = facing.perp(),
  17.             Movement::Foward(steps) => {
  18.                 for _ in 0..steps {
  19.                     let mut next = pos + facing;
  20.                     if !board.in_bounds(next) || board[next] == MaybeTile::Empty {
  21.                         next = pos;
  22.                         while board.in_bounds(next) && board[next] != MaybeTile::Empty {
  23.                             next -= facing;
  24.                         }
  25.                         next += facing;
  26.                     }
  27.                     if board[next] == MaybeTile::Open {
  28.                         pos = next;
  29.                     } else {
  30.                         break;
  31.                     }
  32.                 }
  33.             }
  34.         }
  35.     }
  36.     (pos.y + 1) * 1000 + (pos.x + 1) * 4 + 3 - facing_id(facing)
  37. }
  38.  
  39. pub fn part_2(input: &[String]) -> i64 {
  40.     let (board, path) = parse(input);
  41.     let mut cube = Cube::new(board);
  42.     for movement in path {
  43.         cube.update(movement);
  44.     }
  45.     let mapped = cube.pos + cube.faces[&cube.face].offset * N;
  46.     (mapped.y + 1) * 1000 + (mapped.x + 1) * 4 + 3 - facing_id(cube.facing)
  47. }
  48.  
  49. fn parse(input: &[String]) -> (Grid<MaybeTile>, Path) {
  50.     let end = input.iter().position(String::is_empty).unwrap();
  51.     let width = input.iter().take(end).map(String::len).max().unwrap() as i64;
  52.     let mut board = Grid::new(width, end as i64, MaybeTile::Empty);
  53.     for (y, line) in input.iter().take(end).enumerate() {
  54.         for (x, b) in line.bytes().enumerate() {
  55.             board[v!(x as i64, y as i64)] = match b {
  56.                 b' ' => MaybeTile::Empty,
  57.                 b'.' => MaybeTile::Open,
  58.                 b'#' => MaybeTile::Wall,
  59.                 _ => panic!(),
  60.             };
  61.         }
  62.     }
  63.     (board, Path::new(&input[end + 1]))
  64. }
  65.  
  66. struct Cube {
  67.     faces: HashMap<Direction, Face>,
  68.     face: Direction,
  69.     pos: Vector,
  70.     facing: Vector,
  71. }
  72.  
  73. impl Cube {
  74.     fn update(&mut self, movement: Movement) {
  75.         match movement {
  76.             Movement::Left => self.facing = -self.facing.perp(),
  77.             Movement::Right => self.facing = self.facing.perp(),
  78.             Movement::Foward(steps) => {
  79.                 for _ in 0..steps {
  80.                     let mut next = self.pos + self.facing;
  81.                     let mut next_face = self.face;
  82.                     let mut next_facing = self.facing;
  83.                     if !self.faces[&self.face].grid.in_bounds(next) {
  84.                         next = self.pos;
  85.                         let mut dir = self.faces[&self.face].direction;
  86.                         (next_face, dir) = rotate(self.facing, self.face, dir);
  87.                         while dir != self.faces[&next_face].direction {
  88.                             dir = dir * next_face;
  89.                             next_facing = next_facing.perp();
  90.                             next = v!(N - 1 - next.y, next.x);
  91.                         }
  92.                         if next_facing.x == 0 {
  93.                             next.y = N - 1 - next.y;
  94.                         } else {
  95.                             next.x = N - 1 - next.x;
  96.                         }
  97.                     }
  98.                     if self.faces[&next_face].grid[next] == Tile::Wall {
  99.                         break;
  100.                     } else {
  101.                         self.pos = next;
  102.                         self.face = next_face;
  103.                         self.facing = next_facing;
  104.                     }
  105.                 }
  106.             }
  107.         }
  108.     }
  109.  
  110.     fn new(board: Grid<MaybeTile>) -> Self {
  111.         let mut grids = HashMap::new();
  112.         let mut start = None;
  113.         for y in 0..board.height() / N {
  114.             for x in 0..board.width() / N {
  115.                 let pos = v!(x, y);
  116.                 if board[pos * N] != MaybeTile::Empty {
  117.                     let mut grid = Grid::new(N, N, Tile::Open);
  118.                     for y in 0..N {
  119.                         for x in 0..N {
  120.                             if board[pos * N + v!(x, y)] == MaybeTile::Wall {
  121.                                 grid[v!(x, y)] = Tile::Wall;
  122.                             }
  123.                         }
  124.                     }
  125.                     if start == None {
  126.                         let mut p = ZERO;
  127.                         while grid[p] == Tile::Wall {
  128.                             p += EAST;
  129.                         }
  130.                         start = Some((pos, p));
  131.                     }
  132.                     grids.insert(pos, grid);
  133.                 }
  134.             }
  135.         }
  136.  
  137.         let start = start.unwrap();
  138.         let mut faces = HashMap::new();
  139.         let start_face = Direction::new(Axis::Z, Polarity::Positive);
  140.         let mut added = vec![start_face];
  141.         let grid = grids.remove(&start.0).unwrap();
  142.         faces.insert(
  143.             start_face,
  144.             Face::new(grid, Direction::new(Axis::Y, Polarity::Positive), start.0),
  145.         );
  146.         while faces.len() < 6 {
  147.             let face = added.pop().unwrap();
  148.             let pos = faces[&face].offset;
  149.             for offset in CARDINAL {
  150.                 let pos = pos + offset;
  151.                 if let Some(grid) = grids.remove(&pos) {
  152.                     let (new_face, new_dir) = rotate(offset, face, faces[&face].direction);
  153.                     faces.insert(new_face, Face::new(grid, new_dir, pos));
  154.                     added.push(new_face);
  155.                 }
  156.             }
  157.         }
  158.         Self {
  159.             faces,
  160.             pos: start.1,
  161.             facing: EAST,
  162.             face: start_face,
  163.         }
  164.     }
  165. }
  166.  
  167. fn rotate(facing: Vector, face: Direction, dir: Direction) -> (Direction, Direction) {
  168.     let mut rotation = dir;
  169.     for _ in 0..facing_id(facing) {
  170.         rotation = rotation * face;
  171.     }
  172.     (rotation, dir * (rotation * face))
  173. }
  174.  
  175. struct Face {
  176.     grid: Grid<Tile>,
  177.     direction: Direction,
  178.     offset: Vector,
  179. }
  180.  
  181. impl Face {
  182.     fn new(grid: Grid<Tile>, direction: Direction, offset: Vector) -> Self {
  183.         Self {
  184.             grid,
  185.             direction,
  186.             offset,
  187.         }
  188.     }
  189. }
  190.  
  191. #[derive(Clone, Copy, PartialEq, Eq, Hash)]
  192. struct Direction {
  193.     axis: Axis,
  194.     polarity: Polarity,
  195. }
  196.  
  197. impl Direction {
  198.     fn new(axis: Axis, polarity: Polarity) -> Self {
  199.         Self { axis, polarity }
  200.     }
  201. }
  202.  
  203. impl Mul for Direction {
  204.     type Output = Self;
  205.  
  206.     fn mul(self, rhs: Self) -> Self::Output {
  207.         if self.axis == rhs.axis {
  208.             return self;
  209.         }
  210.         let polarity = self.polarity
  211.             * rhs.polarity
  212.             * match (self.axis, rhs.axis) {
  213.                 (Axis::X, Axis::Y) | (Axis::Y, Axis::Z) | (Axis::Z, Axis::X) => Polarity::Negative,
  214.                 _ => Polarity::Positive,
  215.             };
  216.         let axis = match (self.axis, rhs.axis) {
  217.             (Axis::X, Axis::Y) | (Axis::Y, Axis::X) => Axis::Z,
  218.             (Axis::X, Axis::Z) | (Axis::Z, Axis::X) => Axis::Y,
  219.             _ => Axis::X,
  220.         };
  221.         Self { axis, polarity }
  222.     }
  223. }
  224.  
  225. #[derive(Clone, Copy, PartialEq, Eq, Hash)]
  226. enum Axis {
  227.     X,
  228.     Y,
  229.     Z,
  230. }
  231.  
  232. #[derive(Clone, Copy, PartialEq, Eq, Hash)]
  233. enum Polarity {
  234.     Positive,
  235.     Negative,
  236. }
  237.  
  238. impl Mul for Polarity {
  239.     type Output = Self;
  240.  
  241.     fn mul(self, rhs: Self) -> Self::Output {
  242.         match (self, rhs) {
  243.             (Self::Positive, Self::Positive) => Self::Positive,
  244.             (Self::Positive, Self::Negative) => Self::Negative,
  245.             (Self::Negative, Self::Positive) => Self::Negative,
  246.             (Self::Negative, Self::Negative) => Self::Positive,
  247.         }
  248.     }
  249. }
  250.  
  251. struct Path<'a> {
  252.    line: &'a str,
  253.     i: usize,
  254. }
  255.  
  256. impl<'a> Path<'a> {
  257.     fn new(line: &'a str) -> Self {
  258.        Self { line, i: 0 }
  259.    }
  260. }
  261.  
  262. impl<'a> Iterator for Path<'a> {
  263.    type Item = Movement;
  264.  
  265.    fn next(&mut self) -> Option<Self::Item> {
  266.        if self.i == self.line.len() {
  267.            return None;
  268.        }
  269.        self.i += 1;
  270.        Some(match self.line.as_bytes()[self.i - 1] {
  271.            b'L' => Movement::Left,
  272.            b'R' => Movement::Right,
  273.            _ => {
  274.                let (j, mut k) = (self.i - 1, self.i);
  275.                while k < self.line.len() && (b'0'..=b'9').contains(&self.line.as_bytes()[k]) {
  276.                    k += 1;
  277.                }
  278.                self.i = k;
  279.                Movement::Foward(self.line[j..k].parse().unwrap())
  280.            }
  281.        })
  282.    }
  283. }
  284.  
  285. #[derive(Debug)]
  286. enum Movement {
  287.    Foward(i64),
  288.    Left,
  289.    Right,
  290. }
  291.  
  292. #[derive(Clone, Copy, PartialEq, Eq)]
  293. enum Tile {
  294.    Open,
  295.    Wall,
  296. }
  297.  
  298. #[derive(Clone, Copy, PartialEq, Eq)]
  299. enum MaybeTile {
  300.    Empty,
  301.    Open,
  302.    Wall,
  303. }
  304.  
  305. fn facing_id(facing: Vector) -> i64 {
  306.    match facing {
  307.        NORTH => 0,
  308.        WEST => 1,
  309.        SOUTH => 2,
  310.        EAST => 3,
  311.        _ => unreachable!(),
  312.    }
  313. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement