1use crate::util::parse::*;
7use crate::util::point::*;
8
9type Command = (u8, i32);
10
11pub fn parse(input: &str) -> Vec<Command> {
12 input.lines().map(|line| (line.as_bytes()[0], (&line[1..]).signed())).collect()
13}
14
15pub fn part1(input: &[Command]) -> i32 {
16 let mut position = ORIGIN;
17 let mut direction = Point::new(1, 0);
18
19 for &(command, amount) in input {
20 match command {
21 b'N' => position.y -= amount,
22 b'S' => position.y += amount,
23 b'E' => position.x += amount,
24 b'W' => position.x -= amount,
25 b'L' => direction = rotate(direction, -amount),
26 b'R' => direction = rotate(direction, amount),
27 b'F' => position += direction * amount,
28 _ => unreachable!(),
29 }
30 }
31
32 position.manhattan(ORIGIN)
33}
34
35pub fn part2(input: &[Command]) -> i32 {
36 let mut position = ORIGIN;
37 let mut waypoint = Point::new(10, -1);
38
39 for &(command, amount) in input {
40 match command {
41 b'N' => waypoint.y -= amount,
42 b'S' => waypoint.y += amount,
43 b'E' => waypoint.x += amount,
44 b'W' => waypoint.x -= amount,
45 b'L' => waypoint = rotate(waypoint, -amount),
46 b'R' => waypoint = rotate(waypoint, amount),
47 b'F' => position += waypoint * amount,
48 _ => unreachable!(),
49 }
50 }
51
52 position.manhattan(ORIGIN)
53}
54
55fn rotate(point: Point, amount: i32) -> Point {
56 match amount {
57 90 | -270 => point.clockwise(),
58 180 | -180 => point * -1,
59 270 | -90 => point.counter_clockwise(),
60 _ => unreachable!(),
61 }
62}