Advent of Rust // Day 5

Today’s puzzle was another one where the solutions for the two parts differed only in a minuscule detail.

fn part_one(input: &str) -> String {  
    return process_stacks_and_return_top_items(input, crane_mover_9000);  
}  
  
fn part_two(input: &str) -> String {  
    return process_stacks_and_return_top_items(input, crane_mover_9001);  
}

fn process_stacks_and_return_top_items(input: &str, processor: fn(stacks: &mut Stacks, instruction: Instruction)) -> String {  
    let (stack_input, instruction_input) = input.split_once("\n\n").unwrap();  
  
    let mut stacks = stacks_from_input(stack_input);  
  
    instruction_input.lines()  
        .map(Instruction::from_string)  
        .for_each(|ins| processor(&mut stacks, ins));  
  
    return stacks.keys()  
        .sorted()  
        .map(|k| stacks.get(k).unwrap().last().unwrap())  
        .join("");  
}

For part one, it was just popping and pushing items from one stack to another:

fn crane_mover_9000(stacks: &mut Stacks, instruction: Instruction) {  
    for _i in 0..instruction.count {  
        let item = stacks.get_mut(&instruction.from).unwrap().pop().unwrap();  
        stacks.get_mut(&instruction.to).unwrap().push(item);  
    }  
}  

For part two, it was moving multiple stacks at once:

fn crane_mover_9001(stacks: &mut Stacks, instruction: Instruction) {  
    let from_stack = stacks.get_mut(&instruction.from).unwrap();  
    let from_size = from_stack.len() - instruction.count as usize;  
  
    let items: Vec<String> = from_stack.drain(from_size..).collect();  
  
    stacks.get_mut(&instruction.to).unwrap().extend_from_slice(&items);  
}

Dealing with pointers and ownership is still one of the biggest issues I have with Rust. Firstly, because I haven’t had to deal with pointers in probably two decades and I have gotten used to the convenience of not giving a fuck. Secondly, I still haven’t read the fucking manual. Anyway. I wanted to check out parser combinators in Rust today, but I spent too much time fiddling with mutable pointers, so I took the path of least resistance and went back to using regexes:

struct Instruction {  
    count: u32,  
    from: u32,  
    to: u32,  
}  
  
impl Instruction {  
    fn from_string(input: &str) -> Instruction {  
        let re = Regex::new(r"^move (\d+) from (\d+) to (\d+)$").unwrap();  
        let captures = re.captures(input).unwrap();  
  
        return Instruction {  
            count: captures[1].parse().unwrap(),  
            from: captures[2].parse().unwrap(),  
            to: captures[3].parse().unwrap(),  
        };  
    }  
}

type Stacks = HashMap<u32, Vec<String>>;

fn stacks_from_input(input: &str) -> Stacks {  
    let re = Regex::new(r"( {3}|\[.])").unwrap();  
  
    let mut stacks: Stacks = HashMap::new();  
  
    for line in input.lines().rev().dropping(1) {  
        for (index, capture) in re.captures_iter(line).enumerate() {  
            if capture[1].trim() == "" {  
                continue;  
            }  
  
            let key = (index + 1) as u32;  
            if !stacks.contains_key(&key) {  
                stacks.insert(key, Vec::new());  
            }  
  
            let string = String::from(&capture[1][1..=1]);  
  
            stacks.get_mut(&key).unwrap().push(string);  
        }  
    }  
  
    return stacks;  
}

The full source and solutions for the others puzzles of Advent of Code can be found in my GitHub repository.

See also in Advent of Rust

Comments

You can leave a comment by replying to this post on Mastodon.