137 lines
3.2 KiB
Rust
137 lines
3.2 KiB
Rust
use aoc_runner_derive::{aoc, aoc_generator};
|
|
|
|
use Instruction::*;
|
|
use itertools::Itertools;
|
|
|
|
#[derive(Debug)]
|
|
enum Instruction {
|
|
MoveNorth(i32),
|
|
MoveSouth(i32),
|
|
MoveEast(i32),
|
|
MoveWest(i32),
|
|
TurnLeft(i32),
|
|
TurnRight(i32),
|
|
MoveForward(i32)
|
|
}
|
|
|
|
impl From<(char, i32)> for Instruction {
|
|
fn from(value: (char, i32)) -> Self {
|
|
match value {
|
|
(i, v) if i == 'N' => MoveNorth(v),
|
|
(i, v) if i == 'S' => MoveSouth(v),
|
|
(i, v) if i == 'E' => MoveEast(v),
|
|
(i, v) if i == 'W' => MoveWest(v),
|
|
(i, v) if i == 'L' => TurnLeft(v),
|
|
(i, v) if i == 'R' => TurnRight(v),
|
|
(i, v) if i == 'F' => MoveForward(v),
|
|
_ => unreachable!()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[aoc_generator(day12)]
|
|
fn parse(input: &str) -> Vec<Instruction> {
|
|
input
|
|
.lines()
|
|
.map(|line| {
|
|
(line.chars().next().unwrap(), line[1..].parse::<i32>().unwrap()).into()
|
|
})
|
|
.collect_vec()
|
|
}
|
|
|
|
const DIR_POS_MODIFIER: [(i32, i32); 4] = [(1, 0), (0, -1), (-1, 0), (0, 1)];
|
|
|
|
#[aoc(day12, part1)]
|
|
fn part1(input: &Vec<Instruction>) -> i32 {
|
|
let mut x = 0;
|
|
let mut y = 0;
|
|
let mut direction = 0; // 0 is east, thus 90 is south, 180 is west, and 270 is north
|
|
|
|
for instr in input {
|
|
match instr {
|
|
MoveNorth(val) => y += val,
|
|
MoveSouth(val) => y -= val,
|
|
MoveEast(val) => x += val,
|
|
MoveWest(val) => x -= val,
|
|
TurnLeft(val) => {
|
|
direction -= val;
|
|
if direction < 0 {
|
|
direction += 360;
|
|
}
|
|
},
|
|
TurnRight(val) => {
|
|
direction += val;
|
|
if direction >= 360 {
|
|
direction -= 360
|
|
}
|
|
},
|
|
MoveForward(val) => {
|
|
let (xmod, ymod) = DIR_POS_MODIFIER[(direction / 90) as usize];
|
|
x += xmod * val;
|
|
y += ymod * val;
|
|
},
|
|
}
|
|
}
|
|
|
|
x.abs() + y.abs()
|
|
}
|
|
|
|
#[aoc(day12, part2)]
|
|
fn part2(input: &Vec<Instruction>) -> i32 {
|
|
let mut way_x = 10;
|
|
let mut way_y = 1;
|
|
|
|
let mut ship_x: i32 = 0;
|
|
let mut ship_y: i32 = 0;
|
|
|
|
for instr in input {
|
|
match instr {
|
|
MoveNorth(val) => way_y += val,
|
|
MoveSouth(val) => way_y -= val,
|
|
MoveEast(val) => way_x += val,
|
|
MoveWest(val) => way_x -= val,
|
|
TurnLeft(val) => {
|
|
for _ in 0..(val / 90) {
|
|
let tmp = way_y;
|
|
way_y = way_x;
|
|
way_x = -tmp;
|
|
}
|
|
},
|
|
TurnRight(val) => {
|
|
for _ in 0..(val / 90) {
|
|
let tmp = way_y;
|
|
way_y = -way_x;
|
|
way_x = tmp;
|
|
}
|
|
},
|
|
MoveForward(val) => {
|
|
ship_x += way_x * val;
|
|
ship_y += way_y * val;
|
|
},
|
|
}
|
|
}
|
|
|
|
ship_x.abs() + ship_y.abs()
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
const EX: &str = r"F10
|
|
N3
|
|
F7
|
|
R90
|
|
F11";
|
|
|
|
#[test]
|
|
fn part1_example() {
|
|
assert_eq!(part1(&parse(EX)), 25);
|
|
}
|
|
|
|
#[test]
|
|
fn part2_example() {
|
|
assert_eq!(part2(&parse(EX)), 286);
|
|
}
|
|
} |