#[derive(Debug)] struct Move { num: usize, from: usize, to: usize, } fn main() { let contents = std::fs::read_to_string("data.txt").expect("Failed to read file"); let (crates, moves) = contents.split_once("\n\n").unwrap(); // break into 2 parts let moves: Vec = moves.trim().split('\n').map(line_to_move).collect(); let crate_lines: Vec<&str> = crates.split('\n').collect(); let crate_lines = &crate_lines[0..crate_lines.len() - 1]; // remove the stack numbers line let crate_lines: Vec> = crate_lines.iter().map(|x| clean_crates(&x)).collect(); // Part 1 let mut stacks_part1 = lines_to_crates(&crate_lines); rearrange(&mut stacks_part1, &moves, false); let tops: String = stacks_part1.iter().map(|x| x.last().unwrap()).collect(); println!("Tops part 1: {:?}", tops); // Part 2 let mut stacks_part2 = lines_to_crates(&crate_lines); rearrange(&mut stacks_part2, &moves, true); let tops: String = stacks_part2.iter().map(|x| x.last().unwrap()).collect(); println!("Tops part 2: {:?}", tops); } fn line_to_move(line: &str) -> Move { let parts: Vec<&str> = line.split(' ').collect(); Move { num: parts[1].parse().unwrap(), from: parts[3].parse().unwrap(), to: parts[5].parse().unwrap(), } } // strip spaces and brackets from the crates lines fn clean_crates(line: &str) -> Vec { let chars = line.chars().collect::>(); let chunks = chars.chunks(4).collect::>(); chunks.iter().map(|x| x[1]).collect() } fn lines_to_crates(lines: &Vec>) -> Vec> { let mut crates: Vec> = Vec::new(); for col in 0..lines[0].len() { let mut stack = Vec::new(); for row in (0..lines.len()).rev() { let val = lines[row][col]; if val != ' ' { stack.push(val); } } crates.push(stack); } crates } fn rearrange(crates: &mut Vec>, moves: &Vec, reverse: bool) -> () { for m in moves { let mut temp: Vec = Vec::new(); for _ in 0..m.num { let val = crates[m.from - 1].pop().unwrap(); temp.push(val); } if reverse { temp.reverse(); } crates[m.to - 1].append(&mut temp); } }