#![crate_name = "advent_of_code_day5"] use std::fs; use std::path::{Path}; use regex::Regex; use lazy_static::lazy_static; use std::collections::VecDeque; fn get_crates_from_line(line: &str) -> Vec { lazy_static! { static ref CRATE_RE: Regex = Regex::new(r"\[[A-Z]\]").unwrap(); } let mut crates: Vec = Vec::new(); for cap in CRATE_RE.captures_iter(line) { //println!("Caught with regex: {}", &cap[0]); crates.push(cap[0].chars().nth(1).unwrap()); } return crates; } fn get_instruction_from_line(line: &str) -> Option<[u32; 3]> { lazy_static! { static ref INST_RE: Regex = Regex::new(r"move ([0-9]+) from ([0-9]+) to ([0-9]+)").unwrap(); } if INST_RE.is_match(line) { let cap = INST_RE.captures(line).unwrap(); let instruction: [u32; 3] = [cap[1].parse::().unwrap(), cap[2].parse::().unwrap(), cap[3].parse::().unwrap()]; //println!("Instruction: {} from {} to {}", instruction[0], instruction[1], instruction[2]); return Some(instruction); } else { return None; } } fn vec_contains_char(c: &char, v: &Vec) -> bool { for i in v { if c == i { return true; } } return false; } fn parse_file(input: &str) -> (Vec>, Vec<[u32; 3]>){ // Separate string into stack part and instructions let lines: Vec<&str> = input.split("\n").collect(); let mut stack_column_count: i32 = 0; let mut stack_part: Vec> = Vec::new(); let mut instruction_part: Vec<[u32; 3]> = Vec::new(); for line in lines { //println!("Line: {}", line); // Getting the crate stacks let crate_result = get_crates_from_line(line); if crate_result.len() != 0 { if crate_result.len() > stack_column_count as usize { stack_column_count = crate_result.len() as i32; } for (i, c) in line.chars().enumerate() { if vec_contains_char(&c, &crate_result) { //println!("Found character {} in position {} within result {:?} and line {}", c, i / 4, crate_result, line); while stack_part.len() < (i/4)+1 { // Does stack_part have a stack for slot (i/4)? If not push a new stack stack_part.push(VecDeque::new()); //println!("Created fresh new stack #{}!", stack_part.len()-1); } //println!("Pushing crate {} onto stack slot #{}", c, i/4); stack_part[i/4].push_front(c); } } continue; } // Getting the instructions let inst_result = get_instruction_from_line(line); if match inst_result {Some(_x) => true,None => false,} { //println!("Instruction result: {:?}", inst_result.unwrap()); instruction_part.push(inst_result.unwrap()); continue; } } return (stack_part, instruction_part); } fn simulate_stack_operation(mut stacks: Vec>, instruction: [u32; 3]) -> Vec> { // Simulate the given instruction being executed onto the given stacks and return a new stacks vector with the changes. let amount: u32 = instruction[0]; let source: u32 = instruction[1]-1; let target: u32 = instruction[2]-1; //println!("Executing instruction {:?}", instruction); let mut crane_stack: Vec = Vec::new(); for _ in 0..amount { // fetch amount-many crates onto the crane stack let c: char = stacks[source as usize].pop_back().unwrap(); crane_stack.push(c); println!("Took crate {} from stack #{} and placed it onto the crane stack {:?}", c, source, crane_stack); } for _ in 0..amount { // drop all crates in the crane stack onto the target stack let c: char = crane_stack.pop().unwrap(); stacks[target as usize].push_back(c); println!("Placed crate {} from the crane stack onto target stack #{}", c, target); } return stacks; } fn main() { let input_path = Path::new("./input/input.lst"); let contents = fs::read_to_string(input_path).unwrap(); println!("My given file: \n{}\n\n", contents); let (mut stacks, insts) = parse_file(&contents); println!("Stack part: {:?}", stacks); println!("Instr part: {:?}\n", insts); for instruction in &insts { let next_stacks = simulate_stack_operation(stacks, *instruction); //println!("Stack part: {:?}\n", next_stacks); stacks = next_stacks; } println!("Final stacks looks like this: {:?}", stacks); let mut top_crates: String = "".to_owned(); for stack in &stacks { let mut tmp = [0;4]; top_crates.push_str(&*stack.back().unwrap().encode_utf8(&mut tmp)); } println!("Top-most crates are: {:?}", top_crates); }