krzysz00

Advent of code, day 19

Dec 19th, 2017
94
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. use std::io::{stdin, BufRead};
  2.  
  3. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
  4. enum MazeItem {
  5.     Blank,
  6.     Line,
  7.     Turn,
  8.     Letter(u8),
  9. }
  10.  
  11. impl From<u8> for MazeItem {
  12.     fn from(byte: u8) -> MazeItem {
  13.         match byte as char {
  14.             'A'...'Z' => MazeItem::Letter(byte),
  15.             ' ' => MazeItem::Blank,
  16.             '+' => MazeItem::Turn,
  17.             '-' => MazeItem::Line,
  18.             '|' => MazeItem::Line,
  19.             _ => panic!("Unrecognized character in input"),
  20.         }
  21.     }
  22. }
  23.  
  24. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
  25. enum Direction {
  26.     Up, Down, Left, Right,
  27. }
  28.  
  29. struct State {
  30.     maze: Vec<MazeItem>,
  31.     maze_rs: usize, // _rs is BLIS convention for "row stride", distance to next row
  32.     x: usize,
  33.     y: usize,
  34.     direction: Direction,
  35.     letters: Vec<u8>,
  36. }
  37.  
  38. impl State {
  39.     pub fn new(maze: Vec<MazeItem>, maze_rs: usize) -> State {
  40.         let mut start_x = maze_rs;
  41.         for i in 0..maze_rs {
  42.             if maze[i] == MazeItem::Line {
  43.                 start_x = i;
  44.                 break;
  45.             }
  46.         }
  47.         State { maze: maze, maze_rs: maze_rs, x: start_x, y: 0,
  48.                 direction: Direction::Down, letters: Vec::new() }
  49.     }
  50.  
  51.     pub fn step(&mut self) -> bool {
  52.         let (dx, dy) = match self.direction {
  53.             Direction::Up => (0, -1),
  54.             Direction::Down => (0, 1),
  55.             Direction::Left => (-1, 0),
  56.             Direction::Right => (1, 0),
  57.         };
  58.         self.x = (self.x as isize + dx) as usize;
  59.         self.y = (self.y as isize + dy) as usize;
  60.  
  61.         let idx = self.x + self.y * self.maze_rs;
  62.         if let MazeItem::Letter(l) = self.maze[idx] {
  63.             self.letters.push(l);
  64.         }
  65.  
  66.         if self.maze[idx] == MazeItem::Blank {
  67.             panic!("We stepped on a blank");
  68.         }
  69.         let edge_fall = (self.x == 0 && self.direction == Direction::Left)
  70.             || (self.x >= self.maze_rs - 1 && self.direction == Direction::Right)
  71.             || (self.y == 0 && self.direction == Direction::Up)
  72.             || (idx + self.maze_rs >= self.maze.len() && self.direction == Direction::Down);
  73.         let next_idx = ((idx as isize) + dx + (dy * self.maze_rs as isize)) as usize;
  74.         let need_turn = edge_fall || self.maze[next_idx] == MazeItem::Blank;
  75.         if need_turn && self.maze[idx] == MazeItem::Turn {
  76.             self.direction = match self.direction {
  77.                 Direction::Up | Direction::Down => {
  78.                     if (self.x > 0) && self.maze[idx - 1] != MazeItem::Blank {
  79.                         Direction::Left
  80.                     }
  81.                     else if (self.x + 1 < self.maze_rs) && self.maze[idx + 1] != MazeItem::Blank {
  82.                         Direction::Right
  83.                     }
  84.                     else {
  85.                         return false;
  86.                     }
  87.                 },
  88.                 Direction::Left | Direction::Right => {
  89.                     if (self.y > 0) && self.maze[idx - self.maze_rs] != MazeItem::Blank {
  90.                         Direction::Up
  91.                     }
  92.                     else if (self.y + self.maze_rs < self.maze.len())
  93.                         && (self.maze[idx + self.maze_rs] != MazeItem::Blank) {
  94.                             Direction::Down
  95.                         }
  96.                     else {
  97.                         return false;
  98.                     }
  99.                 }
  100.             };
  101.             true
  102.         }
  103.         else if need_turn {
  104.             false
  105.         }
  106.         else {
  107.             true
  108.         }
  109.     }
  110.  
  111.     pub fn letter_trace(&self) -> &str {
  112.         ::std::str::from_utf8(&self.letters).unwrap()
  113.     }
  114. }
  115.  
  116. fn main() {
  117.     let stdin = stdin();
  118.     let handle = stdin.lock();
  119.     let mut maze = Vec::<MazeItem>::new();
  120.     let mut maze_rs = 0;
  121.     for line in handle.lines() {
  122.         let line = line.expect("I/O error");
  123.         if maze_rs == 0 {
  124.             maze_rs = line.len();
  125.         }
  126.         maze.extend(line.bytes().map(|b: u8| MazeItem::from(b)));
  127.     }
  128.     let mut state = State::new(maze, maze_rs);
  129.  
  130.     let mut n_steps = 2; // start and end will not be counted by loop
  131.     while state.step() { n_steps += 1; }
  132.     println!("{} ({} steps)", state.letter_trace(), n_steps);
  133. }
RAW Paste Data Copied