Skip to main content

year2020/
day12.rs

1use utils::geometry::{Direction, Vec2};
2use utils::prelude::*;
3
4/// Moving a point with translations and rotations.
5#[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                // Rotations are normalised to clockwise
30                ("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]);