fn is_string_numeric(str: &str) -> bool { for c in str.chars() { if !c.is_numeric() { return false; } } true } fn parse_move(crane_move: &str) -> (usize, usize, usize) { let mut crane_move = crane_move .split(" ") .filter(|s| is_string_numeric(s)) .map(|m| m.parse::().unwrap()); ( crane_move.next().unwrap(), crane_move.next().unwrap() - 1, crane_move.next().unwrap() - 1, ) } fn parse_moves(crane_moves: &str) -> Vec<(usize, usize, usize)> { crane_moves.lines().map(parse_move).collect() } fn parse_stacks(stacks: &str) -> Vec { let mut lines: Vec<&str> = stacks.lines().collect(); let mut last_line = lines.pop().unwrap().trim().to_string(); let num_stacks = last_line.pop().unwrap().to_digit(10).unwrap(); let mut parsed_stacks = vec!["".to_string(); num_stacks as usize]; for line in lines { for (idx, c) in line.chars().skip(1).step_by(4).enumerate() { if c.is_alphabetic() { parsed_stacks[idx].insert(0, c); } } } parsed_stacks } pub fn process_part1(input: &str) -> String { let (stacks, crane_moves) = input.split_once("\n\n").unwrap(); let mut stacks = parse_stacks(stacks); let crane_moves = parse_moves(crane_moves); for (iterations, from, to) in crane_moves { for _i in 0..iterations { let popped = stacks[from].pop().unwrap(); stacks[to].push(popped); } } let mut result = "".to_string(); for mut stack in stacks { result.push(stack.pop().unwrap()); } result } pub fn process_part2(input: &str) -> String { let (stacks, crane_moves) = input.split_once("\n\n").unwrap(); let mut stacks = parse_stacks(stacks); let crane_moves = parse_moves(crane_moves); for (iterations, from, to) in crane_moves { let from_len = stacks[from].len(); let from_old = stacks[from].clone(); let (new_from, popped) = from_old.split_at(from_len - iterations); stacks[from] = new_from.to_string(); stacks[to].push_str(popped); } let mut result = "".to_string(); for mut stack in stacks { result.push(stack.pop().unwrap()); } result } #[cfg(test)] mod tests { use super::*; const INPUT: &str = " [D] [N] [C] [Z] [M] [P] 1 2 3 move 1 from 2 to 1 move 3 from 1 to 3 move 2 from 2 to 1 move 1 from 1 to 2"; #[test] fn part1() { let result = process_part1(INPUT); assert_eq!(result, "CMZ"); } #[test] fn part2() { let result = process_part2(INPUT); assert_eq!(result, "MCD"); } }