use std::ops::AddAssign; type Scalar = isize; #[derive(Copy, Clone, Debug)] enum Instruction { Forward(Scalar), Down(Scalar), Up(Scalar), } #[derive(Copy, Clone, Debug)] struct Victor { x: Scalar, y: Scalar, } fn part1(instructions: &[Instruction]) { let directions: Vec = instructions .iter() .map(|&i| Victor::from_direct_instruction(i)) .collect(); let mut position = Victor::new(0, 0); for dir in directions { position += dir; } println!("Solution to part 1: {}", position.x * position.y); } fn part2(instructions: &[Instruction]) { let mut aim: Scalar = 0; let mut position = Victor::new(0, 0); for i in instructions { match &i { Instruction::Down(amount) => aim += amount, Instruction::Up(amount) => aim -= amount, Instruction::Forward(amount) => position += Victor::new(*amount, amount * aim), } } println!("Solution to part 2: {}", position.x * position.y); } pub fn run(input: Vec) { let instructions: Vec = input .into_iter() .map(|s| Instruction::from_str(s)) .collect(); part1(&instructions); part2(&instructions); } impl Instruction { pub fn from_str(instruction_str: S) -> Self where S: AsRef, { let parts: Vec<&str> = instruction_str.as_ref().split_whitespace().collect(); assert_eq!(parts.len(), 2); let scalar = parts[1].parse().expect("Not a valid length"); match parts[0] { "forward" => Self::Forward(scalar), "down" => Self::Down(scalar), "up" => Self::Up(scalar), o => panic!("{} is not a valid instruction", o), } } } impl Victor { pub fn new(x: Scalar, y: Scalar) -> Self { Self { x, y } } pub fn from_direct_instruction(instruction: Instruction) -> Self { use Instruction::*; match instruction { Forward(distance) => Victor::new(distance, 0), Down(distance) => Victor::new(0, distance), Up(distance) => Victor::new(0, -distance), } } } impl AddAssign for Victor { fn add_assign(&mut self, rhs: Self) { self.x += rhs.x; self.y += rhs.y; } }