use aoc_runner_derive::{aoc, aoc_generator}; #[derive(Debug)] pub enum Direction { North, East, South, West, } impl Direction { fn from_int(n: i64) -> Self { match n % 4 { 0 => Self::East, 1 => Self::South, 2 => Self::West, 3 => Self::North, _ => unreachable!(), } } } #[derive(Debug)] pub enum Command { Direction(Direction, i64), Left(i64), Right(i64), Forward(i64), } #[derive(Debug)] pub struct Ship { rot: i64, pos: (i64, i64), wp: (i64, i64), } impl Ship { fn new() -> Self { Self { rot: 0, pos: (0, 0), wp: (10, 1), } } fn facing(&self) -> Direction { Direction::from_int(self.rot) } fn cmd_p1(&mut self, cmd: &Command) { match cmd { Command::Direction(Direction::North, n) => { self.pos.1 += n; } Command::Direction(Direction::South, n) => { self.pos.1 -= n; } Command::Direction(Direction::East, n) => { self.pos.0 += n; } Command::Direction(Direction::West, n) => { self.pos.0 -= n; } Command::Left(n) => { self.rot -= n; } Command::Right(n) => { self.rot += n; } Command::Forward(n) => self.cmd_p1(&Command::Direction(self.facing(), *n)), } } fn cmd_p2(&mut self, cmd: &Command) { match cmd { Command::Direction(Direction::North, n) => { self.wp.1 += n; } Command::Direction(Direction::South, n) => { self.wp.1 -= n; } Command::Direction(Direction::East, n) => { self.wp.0 += n; } Command::Direction(Direction::West, n) => { self.wp.0 -= n; } Command::Right(n) => { let wp = self.wp; self.wp = match n % 4 { 0 => wp, 1 => (wp.1, -wp.0), 2 => (-wp.0, -wp.1), 3 => (-wp.1, wp.0), _ => unreachable!(), }; } Command::Left(n) => { let wp = self.wp; self.wp = match n % 4 { 0 => wp, 1 => (-wp.1, wp.0), 2 => (-wp.0, -wp.1), 3 => (wp.1, -wp.0), _ => unreachable!(), }; } Command::Forward(n) => { self.pos.0 += self.wp.0 * n; self.pos.1 += self.wp.1 * n; } } } } #[aoc_generator(day12)] pub fn input_generator(input: &str) -> Vec { input .lines() .map(|l| { let mut chars = l.chars(); let cmd = chars.next().unwrap(); let num = chars.collect::().parse().unwrap(); match cmd { 'N' => Command::Direction(Direction::North, num), 'S' => Command::Direction(Direction::South, num), 'E' => Command::Direction(Direction::East, num), 'W' => Command::Direction(Direction::West, num), 'L' if num % 90 == 0 => Command::Left((num / 90) % 4), 'R' if num % 90 == 0 => Command::Right((num / 90) % 4), 'F' => Command::Forward(num), _ => panic!("Invalid command: {}", l), } }) .collect::>() } #[aoc(day12, part1)] pub fn solve_part1(input: &[Command]) -> usize { let mut ship = Ship::new(); for cmd in input { ship.cmd_p1(cmd); } return (ship.pos.0.abs() as usize) + (ship.pos.1.abs() as usize); } #[aoc(day12, part2)] pub fn solve_part2(input: &[Command]) -> usize { let mut ship = Ship::new(); for cmd in input { ship.cmd_p2(cmd); } return (ship.pos.0.abs() as usize) + (ship.pos.1.abs() as usize); }