pub fn process_part1(input: &str) -> i32 { let mut sum = 0; let mut number = String::new(); for &byte in input.as_bytes() { if byte == b'-' || byte.is_ascii_digit() { number.push(byte as char); } else if !number.is_empty() { sum += number.parse::().unwrap(); number.clear(); } } sum } pub fn process_part2(input: &str) -> i32 { let red_indices = input .match_indices("red") .map(|(idx, _)| idx) .collect::>(); let mut red_objects = Vec::new(); let mut last_range = (0, 0); for idx in red_indices { if idx > last_range.0 && idx < last_range.1 { continue; } let (left, right) = input.split_at(idx); let open = find_open(left); let close = find_close(right) + idx as u32; let range = (open as usize, close as usize + 1); last_range = range; if !red_objects.contains(&range) { red_objects.push(range); } } red_objects.reverse(); // remove overlaps not caught during creation let mut last_range = (0, 0); let mut no_overlap = Vec::new(); for range in red_objects.clone() { if last_range.0 < range.0 && last_range.1 > range.1 { continue; } last_range = range; no_overlap.push(range); } let mut unreded_input = input.to_owned(); for range in no_overlap { unreded_input.replace_range(range.0..range.1, "0"); } process_part1(&unreded_input) } fn find_open(string: &str) -> u32 { let mut bytes = string.as_bytes().to_vec(); bytes.reverse(); let length = bytes.len(); // count of traversed objects // increments when seeing } decrements when seeing { // while == 0, potentially inside an object // while > 0 peeking inside another object // when < 0 left object red is inside of // when == 0 and encountered [ then inside array let mut curly_count = 0; let mut square_count = 0; let mut idx = length - 1; for byte in bytes { if byte == b'}' { curly_count += 1 } else if byte == b'{' { curly_count -= 1 } else if byte == b'[' { square_count -= 1; } else if byte == b']' { square_count += 1; } if square_count < 0 { return length as u32 - 1; } if curly_count < 0 || idx == 0 { break; } idx -= 1; } if curly_count < 0 { idx as u32 } else { length as u32 } } fn find_close(string: &str) -> u32 { let bytes = string.as_bytes().to_vec(); let length = bytes.len(); // count of traversed objects // increments when seeing { decrements when seeing } // while == 0, potentially inside an object // while > 0 peeking inside another object // when < 0 left object red is inside of // when == 0 and encountered ] then inside array let mut curly_count = 0; let mut square_count = 0; let mut idx = 0; for byte in bytes { if byte == b'}' { curly_count -= 1 } else if byte == b'{' { curly_count += 1 } else if byte == b']' { square_count -= 1; } else if byte == b'[' { square_count += 1; } if square_count < 0 { return 0; } if curly_count < 0 || idx == length { break; } idx += 1; } if curly_count < 0 { idx as u32 } else { 0 } } #[cfg(test)] mod tests { use super::*; #[test] fn part1() { let result_a = process_part1("[1,2,3]"); let result_b = process_part1(r#"{"a":2,"b":4}"#); assert_eq!(result_a, 6); assert_eq!(result_b, 6); let result_a = process_part1("[[[3]]]"); let result_b = process_part1(r#"{"a":{"b":4},"c":-1}"#); assert_eq!(result_a, 3); assert_eq!(result_b, 3); let result_a = process_part1(r#"{"a":[-1,1]}"#); let result_b = process_part1(r#"[-1,{"a":1}]"#); assert_eq!(result_a, 0); assert_eq!(result_b, 0); let result_a = process_part1("[]"); let result_b = process_part1("{}"); assert_eq!(result_a, 0); assert_eq!(result_b, 0); } #[test] fn part2() { //let result_a = process_part2("[1,2,3]"); //let result_b = process_part2(r#"{"a":2,"b":4}"#); //assert_eq!(result_a, 6); //assert_eq!(result_b, 6); //let result_a = process_part2("[[[3]]]"); //let result_b = process_part2(r#"{"a":{"b":4},"c":-1}"#); //assert_eq!(result_a, 3); //assert_eq!(result_b, 3); //let result_a = process_part2(r#"{"a":[-1,1]}"#); //let result_b = process_part2(r#"[-1,{"a":1}]"#); //assert_eq!(result_a, 0); //assert_eq!(result_b, 0); //let result_a = process_part2("[]"); //let result_b = process_part2("{}"); //assert_eq!(result_a, 0); //assert_eq!(result_b, 0); let result_a = process_part2(r#"[1,{"c":"red","b":2},3]"#); assert_eq!(result_a, 4); let result_a = process_part2(r#"{"d":"red","e":[1,2,3,4],"f":5}"#); assert_eq!(result_a, 0); let result_a = process_part2(r#"[1,"red",5]"#); assert_eq!(result_a, 6); } }