From 567ac2ed236d5a126e58c68a50ca91d5fc1bc2dc Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 15 Jan 2022 18:45:43 +0200 Subject: [PATCH] feat: solve day 18 part 1 & 2 --- input/18.txt | 100 ++++++++++++++++++ src/day18.rs | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 3 + 3 files changed, 381 insertions(+) create mode 100644 input/18.txt create mode 100644 src/day18.rs diff --git a/input/18.txt b/input/18.txt new file mode 100644 index 0000000..5e0502e --- /dev/null +++ b/input/18.txt @@ -0,0 +1,100 @@ +[6,[[6,3],[[1,4],[8,4]]]] +[5,[[[0,8],[1,0]],8]] +[[[6,[7,7]],[2,[6,4]]],[2,6]] +[[[[7,4],[2,7]],[4,[1,5]]],[[[0,5],5],[[2,1],[8,2]]]] +[[[[5,9],[7,2]],[0,[9,9]]],[[[5,3],[7,9]],[3,[9,1]]]] +[5,[[3,0],[[8,2],5]]] +[[2,[[0,8],7]],[4,[7,7]]] +[[[[3,4],6],[5,[4,2]]],[[9,[9,5]],2]] +[[7,[0,5]],[[1,3],[7,[4,0]]]] +[[[6,2],3],[[[2,0],9],[5,[7,2]]]] +[[4,[8,6]],8] +[[[9,8],[[7,3],[4,6]]],[5,3]] +[[[0,[8,4]],8],[[5,[4,7]],[5,9]]] +[[[[0,8],[3,7]],[5,1]],[[5,6],2]] +[[[[5,8],0],[[3,0],3]],[[6,5],[[8,0],[3,9]]]] +[[[8,[5,6]],[6,4]],[8,0]] +[7,[[5,[3,8]],3]] +[[[4,[2,0]],2],[[[8,1],[5,8]],5]] +[9,[[[6,6],[8,1]],[[7,9],9]]] +[[[6,0],[[7,2],9]],[[[7,3],[1,1]],0]] +[[[[7,8],[0,3]],[5,9]],[[2,[4,3]],7]] +[[[3,1],[3,[6,3]]],[[6,[8,9]],7]] +[[[[1,1],[0,5]],[8,1]],[0,[8,[1,4]]]] +[[[6,[8,6]],[7,8]],[[7,3],[3,[5,8]]]] +[[[2,5],[[6,8],[4,5]]],[[2,[8,2]],[2,[3,2]]]] +[[[[9,2],0],5],0] +[[7,[[3,7],[0,9]]],[6,[1,[6,9]]]] +[[[[4,5],5],5],4] +[[[6,[6,9]],[8,3]],9] +[[[[2,7],[8,6]],0],[2,[4,9]]] +[[[4,[9,8]],[7,6]],[7,[[2,7],[2,7]]]] +[[[0,8],[4,[5,9]]],[[4,[1,0]],[6,8]]] +[[[2,4],9],[[[7,9],5],[0,5]]] +[[[3,[8,6]],6],[[8,[6,7]],[[6,1],[2,1]]]] +[[[0,[0,5]],[[0,5],4]],9] +[[[[0,0],7],8],[[8,[4,6]],9]] +[[[1,[1,1]],[3,[2,5]]],[6,6]] +[[[[3,7],[6,1]],[5,4]],[[0,[2,6]],[0,1]]] +[[1,1],[3,4]] +[9,[[4,[7,8]],[3,4]]] +[[[[5,3],[5,9]],9],[[[2,4],[2,7]],[[6,3],[1,8]]]] +[[[2,[2,2]],[[8,7],9]],[[[4,6],[5,3]],[[2,6],9]]] +[[[3,8],[[5,7],7]],[[[0,9],3],1]] +[[[6,[1,9]],[2,1]],[[[7,0],[2,1]],8]] +[[[8,[9,9]],1],[[4,1],[[2,8],1]]] +[[[2,[3,7]],[[2,4],[3,5]]],[[3,[1,9]],[[1,3],[1,7]]]] +[[[[4,3],8],3],[[6,[1,7]],[[4,2],9]]] +[[[[1,9],1],[[0,7],[9,4]]],[[[7,2],[0,1]],8]] +[9,5] +[[[[6,4],4],[[3,4],0]],[[9,[7,6]],[[3,4],[7,1]]]] +[[0,2],[[[4,9],[3,4]],[2,[3,9]]]] +[[[[8,9],9],[[6,4],[2,9]]],[[4,5],[[1,8],2]]] +[[[6,[9,5]],[4,[1,0]]],[[[4,1],[3,5]],[3,3]]] +[[[7,1],[[5,4],8]],[[0,[9,4]],7]] +[[[4,[0,3]],[[0,2],8]],[[0,[9,6]],[[6,3],[3,2]]]] +[[[[5,5],8],[[4,5],3]],[3,[[0,2],0]]] +[[[[9,5],[1,0]],[[9,1],[0,9]]],[[1,[9,1]],[1,3]]] +[[9,[[5,7],8]],[[9,[9,3]],[3,[0,1]]]] +[[[5,6],[9,8]],[2,9]] +[[[9,[3,8]],[9,0]],[[8,[6,2]],1]] +[3,[4,[1,[0,4]]]] +[[9,[[8,5],[8,0]]],[[1,6],[8,4]]] +[[7,[[6,8],5]],[[9,[1,3]],[[6,5],[0,8]]]] +[[[6,0],[9,[3,5]]],[8,6]] +[[[1,[2,3]],[[5,2],4]],[1,[[7,3],2]]] +[[[2,[1,1]],3],[[8,[5,5]],[[7,5],[8,9]]]] +[[[4,0],[8,6]],[[[7,1],7],0]] +[2,6] +[[[[5,4],[9,7]],4],[0,6]] +[[4,[0,5]],[1,[[1,6],[6,2]]]] +[[[7,8],[0,6]],[0,[[2,9],[1,5]]]] +[1,[[[4,4],1],[[3,2],[2,5]]]] +[[[[9,8],[2,4]],[1,2]],[[[5,1],9],[[0,8],[5,2]]]] +[[8,[[2,6],[4,6]]],[[0,[2,9]],[[2,2],[7,2]]]] +[[[7,[8,1]],[[8,8],7]],[3,[7,[7,9]]]] +[[6,[[3,1],[3,6]]],[[[5,8],[9,8]],[2,[7,4]]]] +[[[4,[2,0]],[3,[3,3]]],[[6,[8,5]],5]] +[[[3,2],3],[[8,2],8]] +[[7,[[8,7],[5,8]]],[[2,0],[7,7]]] +[[[[3,3],1],[[5,1],4]],[[4,3],[[4,9],8]]] +[[[0,[5,8]],7],[4,9]] +[[0,[[7,7],[1,1]]],[[0,[5,0]],[4,5]]] +[[[[2,8],[1,6]],[[7,3],9]],[[2,8],[6,2]]] +[[1,[4,7]],[8,0]] +[3,[[[6,1],9],[[1,1],5]]] +[[[[3,0],[9,8]],[6,[8,3]]],3] +[4,[[1,[8,1]],[[6,0],2]]] +[[4,[4,[0,3]]],[[[7,5],[0,2]],[[9,7],[6,5]]]] +[[0,[4,[6,1]]],[[[1,9],[6,0]],9]] +[[[[0,2],[8,4]],[2,3]],[[9,[8,4]],1]] +[[[[1,2],[7,7]],[[3,8],3]],[[[1,1],[7,5]],6]] +[[[[1,8],[8,4]],[[4,0],1]],[0,[1,[9,4]]]] +[[[3,1],[9,5]],[[[9,5],4],[[8,7],4]]] +[[[6,[3,0]],0],[[[6,9],7],[[6,1],[6,6]]]] +[[[[9,6],[4,4]],5],9] +[[5,[[6,0],0]],1] +[3,[0,[4,[9,0]]]] +[[[5,[2,2]],3],5] +[[2,3],[9,[6,7]]] +[[[[6,8],[7,9]],[4,7]],[[1,2],[0,1]]] diff --git a/src/day18.rs b/src/day18.rs new file mode 100644 index 0000000..100e46c --- /dev/null +++ b/src/day18.rs @@ -0,0 +1,278 @@ +// Solution gotten from: https://github.com/AxlLind/AdventOfCode2021/blob/main/src/bin/18.rs + +fn parse_snailfish(line: &str) -> Vec<(i32, u8)> { + let mut depth = 0; + let mut nums = Vec::new(); + for c in line.chars() { + match c { + '[' => depth += 1, + ']' => depth -= 1, + ',' => {}, + _ => nums.push(((c as u8 - b'0') as i32, depth)) + } + } + return nums; +} + +fn find_deepest_index(num: &Vec<(i32, u8)>) -> usize { + let mut deepest_index = 0; + let mut deepest_depth = 0; + for i in 0..num.len() { + let depth = num[i].1; + if deepest_depth < depth { + deepest_depth = depth; + deepest_index = i; + } + } + return deepest_index; +} + +pub fn parse_input(input: &str) -> Vec> { + let mut nums = Vec::new(); + for line in input.lines() { + nums.push(parse_snailfish(line)); + } + return nums; +} + +fn add_snailfish(a: &Vec<(i32, u8)>, b: &Vec<(i32, u8)>) -> Vec<(i32, u8)> { + let mut added = Vec::new(); + for (num, depth) in a { + added.push((*num, depth+1)); + } + for (num, depth) in b { + added.push((*num, depth+1)); + } + return added; +} + +fn try_exploding(num: &mut Vec<(i32, u8)>) -> bool { + let i = find_deepest_index(num); + if num[i].1 < 5 { return false; } + let (left_num, depth) = num[i]; + let right_num = num.remove(i+1).0; + if i > 0 { + num[i-1].0 += left_num; + } + if i+1 < num.len() { + num[i+1].0 += right_num; + } + num[i] = (0, depth-1); + return true; +} + +fn try_splitting(num: &mut Vec<(i32, u8)>) -> bool { + let target = match num.iter().position(|&(n,_)| n > 9) { + Some(i) => i, + None => return false, + }; + let (x, depth) = num[target]; + num[target] = (x/2, depth+1); + num.insert(target+1, ((x+1)/2, depth+1)); + return true; +} + +fn reduce_snailfish(num: &mut Vec<(i32, u8)>) { + loop { + if try_exploding(num) { continue; } + if try_splitting(num) { continue; } + break; + } +} + +fn get_magnitude(mut num: Vec<(i32, u8)>) -> i32 { + while num.len() > 1 { + let i = find_deepest_index(&num); + let (left_num, depth) = num[i]; + let right_num = num[i+1].0; + num[i] = (3*left_num + 2*right_num, depth-1); + num.remove(i+1); + } + num[0].0 +} + +fn add_and_reduce(a: &Vec<(i32, u8)>, b: &Vec<(i32, u8)>) -> Vec<(i32, u8)> { + let mut result = add_snailfish(a, b); + reduce_snailfish(&mut result); + return result; +} + +fn sum(nums: &Vec>) -> Vec<(i32, u8)> { + let mut result = nums[0].clone(); + for i in 1..nums.len() { + result = add_snailfish(&result, &nums[i]); + reduce_snailfish(&mut result); + } + return result; +} + +pub fn part1(nums: &Vec>) -> i32 { + return get_magnitude(sum(nums)); +} + +pub fn part2(nums: &Vec>) -> i32 { + let mut max_magnitude = 0; + let n = nums.len(); + for i in 0..n { + for j in 0..n-1 { + let a = &nums[i]; + let b = &nums[j]; + max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(a, b))); + max_magnitude = max_magnitude.max(get_magnitude(add_and_reduce(b, a))); + } + } + return max_magnitude; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_example() { + let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] +[[[5,[2,8]],4],[5,[[9,9],0]]] +[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] +[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] +[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]] +[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]] +[[[[5,4],[7,7]],8],[[8,3],8]] +[[9,3],[[9,9],[6,[4,9]]]] +[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); + let result = part1(&nums); + assert_eq!(result, 4140); + } + + #[test] + fn part2_example() { + let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] +[[[5,[2,8]],4],[5,[[9,9],0]]] +[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] +[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] +[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]] +[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]] +[[[[5,4],[7,7]],8],[[8,3],8]] +[[9,3],[[9,9],[6,[4,9]]]] +[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] +[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); + let result = part2(&nums); + assert_eq!(result, 3993); + } + + fn test_explosion(initial: &str, expected: &str) { + let mut num = parse_snailfish(initial); + try_exploding(&mut num); + assert_eq!(num, parse_snailfish(expected)); + } + + #[test] + fn exploding_1() { + test_explosion("[[[[[9,8],1],2],3],4]", "[[[[0,9],2],3],4]"); + } + #[test] + fn exploding_2() { + test_explosion("[7,[6,[5,[4,[3,2]]]]]", "[7,[6,[5,[7,0]]]]"); + } + #[test] + fn exploding_3() { + test_explosion("[[6,[5,[4,[3,2]]]],1]", "[[6,[5,[7,0]]],3]"); + } + #[test] + fn exploding_4() { + test_explosion("[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]"); + } + #[test] + fn exploding_5() { + test_explosion("[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[7,0]]]]"); + } + + fn test_sum(nums: Vec<&str>, expected: &str) { + let mut parsed_nums = Vec::new(); + for num in nums { + parsed_nums.push(parse_snailfish(num)); + } + assert_eq!(sum(&parsed_nums), parse_snailfish(expected)); + } + + #[test] + fn sum_1() { + let nums = vec![ + "[1,1]", + "[2,2]", + "[3,3]", + "[4,4]" + ]; + test_sum(nums, "[[[[1,1],[2,2]],[3,3]],[4,4]]"); + } + #[test] + fn sum_2() { + let nums = vec![ + "[1,1]", + "[2,2]", + "[3,3]", + "[4,4]", + "[5,5]" + ]; + test_sum(nums, "[[[[3,0],[5,3]],[4,4]],[5,5]]"); + } + #[test] + fn sum_3() { + let nums = vec![ + "[1,1]", + "[2,2]", + "[3,3]", + "[4,4]", + "[5,5]", + "[6,6]", + ]; + test_sum(nums, "[[[[5,0],[7,4]],[5,5]],[6,6]]"); + } + #[test] + fn sum_4() { + let nums = vec![ + "[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]", + "[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]", + "[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]", + "[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]", + "[7,[5,[[3,8],[1,4]]]]", + "[[2,[2,2]],[8,[8,1]]]", + "[2,9]", + "[1,[[[9,3],9],[[9,0],[0,7]]]]", + "[[[5,[7,4]],7],1]", + "[[[[4,2],2],6],[8,7]]" + ]; + test_sum(nums, "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]"); + } + + fn test_magnitude(initial: &str, expected: i32) { + let num = parse_snailfish(initial); + assert_eq!(get_magnitude(num), expected); + } + + #[test] + fn magnitude_1() { + test_magnitude("[[1,2],[[3,4],5]]", 143); + } + #[test] + fn magnitude_2() { + test_magnitude("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]", 1384); + } + #[test] + fn magnitude_3() { + test_magnitude("[[[[1,1],[2,2]],[3,3]],[4,4]]", 445); + } + #[test] + fn magnitude_4() { + test_magnitude("[[[[3,0],[5,3]],[4,4]],[5,5]]", 791); + } + #[test] + fn magnitude_5() { + test_magnitude("[[[[5,0],[7,4]],[5,5]],[6,6]]", 1137); + } + #[test] + fn magnitude_6() { + test_magnitude("[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]", 3488); + } +} + diff --git a/src/main.rs b/src/main.rs index 3fd5c79..3718242 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ mod day14; mod day15; mod day16; mod day17; +mod day18; use std::{env, process}; use std::fs::File; @@ -65,6 +66,8 @@ fn run(day: i32, part: i32, input_filename: &str) { "16.2" => println!("{}", day16::part2(&day16::parse_input(&contents))), "17.1" => println!("{}", day17::part1(&day17::parse_input(&contents))), "17.2" => println!("{}", day17::part2(&day17::parse_input(&contents))), + "18.1" => println!("{}", day18::part1(&day18::parse_input(&contents))), + "18.2" => println!("{}", day18::part2(&day18::parse_input(&contents))), _ => println!("Day {} part {} not found", day, part) } }