2021-12-02 06:37:07 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
use aoc_runner_derive::{aoc, aoc_generator};
|
2021-12-04 22:49:01 +00:00
|
|
|
use yap::{IntoTokens, Tokens};
|
|
|
|
|
|
|
|
use crate::parsing::parse_number;
|
2021-12-02 06:37:07 +00:00
|
|
|
|
|
|
|
#[aoc_generator(day2)]
|
|
|
|
pub fn parse_movements(input: &str) -> Vec<Movement> {
|
|
|
|
input
|
|
|
|
.split('\n')
|
|
|
|
.map(|input| input.parse().unwrap())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[aoc(day2, part1)]
|
|
|
|
pub fn part1(input: &[Movement]) -> isize {
|
2021-12-04 22:49:01 +00:00
|
|
|
NaiveState::default().movements(input)
|
2021-12-02 06:37:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[aoc(day2, part2)]
|
|
|
|
pub fn part2(input: &[Movement]) -> isize {
|
2021-12-04 22:49:01 +00:00
|
|
|
CorrectState::default().movements(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait State {
|
|
|
|
fn movement(&mut self, movement: &Movement);
|
|
|
|
fn depth(&self) -> isize;
|
|
|
|
fn horizontal_pos(&self) -> isize;
|
|
|
|
fn result(&self) -> isize {
|
|
|
|
self.depth() * self.horizontal_pos()
|
|
|
|
}
|
|
|
|
fn movements(&mut self, moves: &[Movement]) -> isize {
|
|
|
|
for movement in moves {
|
|
|
|
self.movement(&movement);
|
|
|
|
}
|
|
|
|
self.result()
|
|
|
|
}
|
2021-12-02 06:37:07 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 22:49:01 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct CorrectState {
|
2021-12-02 06:37:07 +00:00
|
|
|
horizontal_pos: isize,
|
|
|
|
depth: isize,
|
|
|
|
aim: isize,
|
|
|
|
}
|
|
|
|
|
2021-12-04 22:49:01 +00:00
|
|
|
impl State for CorrectState {
|
2021-12-02 06:37:07 +00:00
|
|
|
fn movement(&mut self, movement: &Movement) {
|
|
|
|
match movement {
|
|
|
|
Movement::Forward(units) => {
|
|
|
|
self.horizontal_pos += units;
|
|
|
|
self.depth += units * self.aim;
|
|
|
|
}
|
|
|
|
Movement::Down(units) => self.aim += units,
|
|
|
|
Movement::Up(units) => self.aim -= units,
|
|
|
|
}
|
|
|
|
}
|
2021-12-04 22:49:01 +00:00
|
|
|
|
|
|
|
fn depth(&self) -> isize {
|
|
|
|
self.depth
|
|
|
|
}
|
|
|
|
|
|
|
|
fn horizontal_pos(&self) -> isize {
|
|
|
|
self.horizontal_pos
|
|
|
|
}
|
2021-12-02 06:37:07 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 22:49:01 +00:00
|
|
|
#[derive(Default)]
|
2021-12-02 06:37:07 +00:00
|
|
|
pub struct NaiveState {
|
|
|
|
horizontal_pos: isize,
|
|
|
|
depth: isize,
|
|
|
|
}
|
|
|
|
|
2021-12-04 22:49:01 +00:00
|
|
|
impl State for NaiveState {
|
2021-12-02 06:37:07 +00:00
|
|
|
fn movement(&mut self, movement: &Movement) {
|
|
|
|
match movement {
|
|
|
|
Movement::Forward(units) => self.horizontal_pos += units,
|
|
|
|
Movement::Down(units) => self.depth += units,
|
|
|
|
Movement::Up(units) => self.depth -= units,
|
|
|
|
}
|
|
|
|
}
|
2021-12-04 22:49:01 +00:00
|
|
|
|
|
|
|
fn depth(&self) -> isize {
|
|
|
|
self.depth
|
|
|
|
}
|
|
|
|
|
|
|
|
fn horizontal_pos(&self) -> isize {
|
|
|
|
self.horizontal_pos
|
|
|
|
}
|
2021-12-02 06:37:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Movement {
|
|
|
|
Forward(isize),
|
|
|
|
Down(isize),
|
|
|
|
Up(isize),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Movement {
|
|
|
|
type Err = ();
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2021-12-04 22:49:01 +00:00
|
|
|
let mut tokens = s.into_tokens();
|
|
|
|
yap::one_of!(ts from &mut tokens;
|
|
|
|
ts.tokens("forward ".chars()).then(|| parse_number(ts).map(|num| Movement::Forward(num))).flatten(),
|
|
|
|
ts.tokens("down ".chars()).then(|| parse_number(ts).map(|num| Movement::Down(num))).flatten(),
|
|
|
|
ts.tokens("up ".chars()).then(|| parse_number(ts).map(|num| Movement::Up(num))).flatten(),
|
|
|
|
).ok_or(())
|
2021-12-02 06:37:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
const EXAMPLE_INPUT: &str = "forward 5
|
|
|
|
down 5
|
|
|
|
forward 8
|
|
|
|
up 3
|
|
|
|
down 8
|
|
|
|
forward 2";
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part1_example() {
|
|
|
|
let input = super::parse_movements(EXAMPLE_INPUT);
|
|
|
|
let result = super::part1(&input);
|
|
|
|
assert_eq!(result, 150);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part2_example() {
|
|
|
|
let input = super::parse_movements(EXAMPLE_INPUT);
|
|
|
|
let result = super::part2(&input);
|
|
|
|
assert_eq!(result, 900);
|
|
|
|
}
|
|
|
|
}
|