1use utils::geometry::{Direction, Vec2};
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day12 {
7 part1: u32,
8 part2: u32,
9}
10
11#[derive(Copy, Clone, Debug)]
12enum Instruction {
13 Move(Direction, u16),
14 Forward(u16),
15 Rotate90,
16 Rotate180,
17 Rotate270,
18}
19
20impl Day12 {
21 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
22 let instruction = parser::parse_tree!(
23 (b'N', v @ parser::u16()) => Instruction::Move(Direction::Up, v),
24 (b'S', v @ parser::u16()) => Instruction::Move(Direction::Down, v),
25 (b'E', v @ parser::u16()) => Instruction::Move(Direction::Right, v),
26 (b'W', v @ parser::u16()) => Instruction::Move(Direction::Left, v),
27 (b'F', v @ parser::u16()) => Instruction::Forward(v),
28 (b'L') =>> {
29 ("90") => Instruction::Rotate270,
31 ("180") => Instruction::Rotate180,
32 ("270") => Instruction::Rotate90,
33 },
34 (b'R') =>> {
35 ("90") => Instruction::Rotate90,
36 ("180") => Instruction::Rotate180,
37 ("270") => Instruction::Rotate270,
38 },
39 )
40 .with_eol();
41
42 let (mut ship1, mut direction) = (Vec2::ORIGIN, Vec2::RIGHT);
43 let (mut ship2, mut waypoint) = (Vec2::ORIGIN, Vec2::new(10, 1));
44 for item in instruction.parse_iterator(input) {
45 match item? {
46 Instruction::Move(dir, v) => {
47 let movement = Vec2::from(dir) * i32::from(v);
48 ship1 += movement;
49 waypoint += movement;
50 }
51 Instruction::Forward(v) => {
52 ship1 += direction * i32::from(v);
53 ship2 += waypoint * i32::from(v);
54 }
55 Instruction::Rotate90 => {
56 (direction, waypoint) = (direction.turn_right(), waypoint.turn_right());
57 }
58 Instruction::Rotate180 => (direction, waypoint) = (-direction, -waypoint),
59 Instruction::Rotate270 => {
60 (direction, waypoint) = (direction.turn_left(), waypoint.turn_left());
61 }
62 }
63 }
64
65 Ok(Self {
66 part1: ship1.manhattan_distance(),
67 part2: ship2.manhattan_distance(),
68 })
69 }
70
71 #[must_use]
72 pub fn part1(&self) -> u32 {
73 self.part1
74 }
75
76 #[must_use]
77 pub fn part2(&self) -> u32 {
78 self.part2
79 }
80}
81
82examples!(Day12 -> (u32, u32) [
83 {input: "F10\nN3\nF7\nR90\nF11", part1: 25, part2: 286},
84]);