use aoc_runner_derive::{aoc, aoc_generator}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Button { Directional(DirectionalButton), Numeric(NumericButton), } impl Button { fn pos(&self) -> (isize, isize) { match self { Button::Directional(button) => button.pos(), Button::Numeric(button) => button.pos(), } } fn to(&self, other: &Button) -> Vec { match (self, other) { (Button::Directional(a), Button::Directional(b)) => a.to(b), (Button::Numeric(a), Button::Numeric(b)) => a.to(b), _ => unimplemented!(), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum DirectionalButton { Up, Down, Left, Right, A, } impl DirectionalButton { fn pos(&self) -> (isize, isize) { match self { DirectionalButton::Up => (1, 0), DirectionalButton::Down => (1, 1), DirectionalButton::Left => (0, 1), DirectionalButton::Right => (2, 1), DirectionalButton::A => (2, 0), } } fn to(&self, other: &DirectionalButton) -> Vec { let start = self.pos(); let end = other.pos(); let mut x = if start.0 < end.0 { vec![DirectionalButton::Right; (end.0 - start.0) as usize] } else { vec![DirectionalButton::Left; (start.0 - end.0) as usize] }; let mut y = if start.1 < end.1 { vec![DirectionalButton::Down; (end.1 - start.1) as usize] } else { vec![DirectionalButton::Up; (start.1 - end.1) as usize] }; if end.0 == 0 { y.append(&mut x); y } else { x.append(&mut y); x } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum NumericButton { Number(u8), A, } impl NumericButton { fn pos(&self) -> (isize, isize) { match self { NumericButton::Number(1) => (0, 2), NumericButton::Number(2) => (1, 2), NumericButton::Number(3) => (2, 2), NumericButton::Number(4) => (0, 1), NumericButton::Number(5) => (1, 1), NumericButton::Number(6) => (2, 1), NumericButton::Number(7) => (0, 0), NumericButton::Number(8) => (1, 0), NumericButton::Number(9) => (2, 0), NumericButton::Number(0) => (1, 3), NumericButton::A => (2, 3), _ => unreachable!(), } } fn to(&self, other: &NumericButton) -> Vec { let start = self.pos(); let end = other.pos(); let mut x = if start.0 < end.0 { vec![DirectionalButton::Right; (end.0 - start.0) as usize] } else { vec![DirectionalButton::Left; (start.0 - end.0) as usize] }; let mut y = if start.1 < end.1 { vec![DirectionalButton::Down; (end.1 - start.1) as usize] } else { vec![DirectionalButton::Up; (start.1 - end.1) as usize] }; if end.1 != 3 { y.append(&mut x); y } else { x.append(&mut y); x } } } type Input = Vec>; #[aoc_generator(day21)] fn parse(input: &str) -> Input { input .lines() .map(|line| { line.chars() .map(|c| match c { '0' => NumericButton::Number(0), '1' => NumericButton::Number(1), '2' => NumericButton::Number(2), '3' => NumericButton::Number(3), '4' => NumericButton::Number(4), '5' => NumericButton::Number(5), '6' => NumericButton::Number(6), '7' => NumericButton::Number(7), '8' => NumericButton::Number(8), '9' => NumericButton::Number(9), 'A' => NumericButton::A, _ => unreachable!(), }) .map(Button::Numeric) .collect() }) .collect() } #[aoc(day21, part1)] fn part1(input: &Input) -> usize { input .iter() .cloned() .map(|instruction| { let mut instructions = vec![]; let mut stack = vec![]; let num_robots = 3; let mut positions = vec![Button::Numeric(NumericButton::A)]; for _ in 1..num_robots { positions.push(Button::Directional(DirectionalButton::A)); } for button in instruction.iter().rev() { stack.push((0, *button)); } while let Some((robot, button)) = stack.pop() { if robot == num_robots { instructions.push(button); continue; } println!( "move {} from {:?} to {:?} = {:?}", robot, positions[robot].pos(), button.pos(), button ); let instructions = positions[robot].to(&button); stack.push((robot + 1, Button::Directional(DirectionalButton::A))); for instruction in instructions.iter().rev() { stack.push((robot + 1, Button::Directional(*instruction))); } positions[robot] = button; } let numeric = instruction .iter() .filter_map(|button| match button { Button::Numeric(NumericButton::Number(numeric)) => Some(numeric), _ => None, }) .fold(String::new(), |mut acc, num| { acc.push_str(&num.to_string()); acc }) .parse::() .unwrap(); dbg!(instructions.len()); println!( "{}", instructions .iter() .map(|instruction| match instruction { Button::Directional(DirectionalButton::Up) => '^', Button::Directional(DirectionalButton::Down) => 'v', Button::Directional(DirectionalButton::Left) => '<', Button::Directional(DirectionalButton::Right) => '>', Button::Directional(DirectionalButton::A) => 'A', _ => unreachable!(), }) .collect::() ); numeric * instructions.len() }) .sum() } // #[aoc(day21, part2)] // fn part2(input: &Input) -> usize { // todo!() // } #[cfg(test)] mod tests { use super::*; #[test] fn part1_example() { // assert_eq!(part1(&parse("179A")), 68 * 179); assert_eq!(part1(&parse("379A")), 64 * 379); assert_eq!(part1(&parse("456A")), 64 * 456); assert_eq!(part1(&parse("980A")), 60 * 980); assert_eq!(part1(&parse("029A")), 68 * 29); } // #[test] // fn part2_example() { // assert_eq!(part2(&parse("")), 0); // } } // 89666 too low // 97150 wrong