156 lines
4.1 KiB
Rust
156 lines
4.1 KiB
Rust
|
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<Command> {
|
||
|
input
|
||
|
.lines()
|
||
|
.map(|l| {
|
||
|
let mut chars=l.chars();
|
||
|
let cmd=chars.next().unwrap();
|
||
|
let num = chars.collect::<String>().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::<Vec<Command>>()
|
||
|
}
|
||
|
|
||
|
#[aoc(day12, part1)]
|
||
|
pub fn solve_part1(input: &Vec<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: &Vec<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);
|
||
|
}
|