use std::collections::VecDeque; use std::fmt::Display; use itertools::Itertools; pub fn day18() { assert_eq!( parse("[[1,2],3]"), SnailNum { tokens: vec![ Token::Start, Token::Start, Token::Number(1), Token::Number(2), Token::End, Token::Number(3), Token::End, ], } ); let pairs = [ ("[[[[[9,8],1],2],3],4]", "[[[[0,9],2],3],4]"), ("[7,[6,[5,[4,[3,2]]]]]", "[7,[6,[5,[7,0]]]]"), ("[[6,[5,[4,[3,2]]]],1]", "[[6,[5,[7,0]]],3]"), ( "[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", ), ( "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[7,0]]]]", ), ]; for (input, expected) in pairs { let mut num = parse(input); assert!(num.try_explode()); assert_eq!(num, parse(expected)); } assert_eq!( parse("[[[[4,3],4],4],[7,[[8,4],9]]]").add(parse("[1,1]")), parse("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]") ); // assert_eq!( // sum_all(&["[1,1]", "[2,2]", "[3,3]", "[4,4]"]), // parse("[[[[1,1],[2,2]],[3,3]],[4,4]]") // ); // assert_eq!( // sum_all(&["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]"]), // parse("[[[[3,0],[5,3]],[4,4]],[5,5]]") // ); // assert_eq!( // sum_all(&["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]", "[6,6]"]), // parse("[[[[5,0],[7,4]],[5,5]],[6,6]]") // ); assert_eq!(parse("[[1,2],[[3,4],5]]").magnitude(), 143); assert_eq!(parse("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]").magnitude(), 1384); assert_eq!( parse("[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]").magnitude(), 3488 ); let input = include_str!("../input/day18.txt"); let nums = input.trim().lines().map(|l| parse(l.trim())); let sum = nums.clone().reduce(|a, b| a.add(b)).unwrap(); println!("part 1: {}", sum.magnitude()); let max_sum_magnitude = nums .clone() .cartesian_product(nums) .map(|(a, b)| a.add(b).magnitude()) .max() .unwrap(); println!("part 2: {}", max_sum_magnitude); } #[derive(Debug, PartialEq, Clone)] struct SnailNum { tokens: Vec, } #[derive(Debug, Clone, Copy, PartialEq)] enum Token { Start, End, Number(usize), } impl Token { fn is_num(&self) -> bool { match self { Token::Number(_) => true, _ => false, } } fn as_num(&self) -> &usize { match self { Token::Number(n) => n, _ => panic!(), } } fn as_num_mut(&mut self) -> &mut usize { match self { Token::Number(n) => n, _ => panic!(), } } } fn parse(s: &str) -> SnailNum { let mut v = vec![]; let mut it = s.chars().peekable(); let mut depth = 0; while let Some(c) = it.next() { match c { '[' => { depth += 1; v.push(Token::Start); } ']' => { depth -= 1; v.push(Token::End); } ',' => (), '0'..='9' => { let mut n = c.to_digit(10).unwrap() as usize; while let Some(c @ '0'..='9') = it.peek() { n *= 10; n += c.to_digit(10).unwrap() as usize; it.next(); } v.push(Token::Number(n)); } _ => panic!(), } } assert_eq!(depth, 0); SnailNum { tokens: v } } impl Display for SnailNum { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { #[derive(PartialEq)] enum State { Left, Right, } let mut state = VecDeque::new(); for (i, t) in self.tokens.iter().enumerate() { match t { Token::Start => { write!(f, "[").expect("write"); state.push_front(State::Left); } Token::End => { write!(f, "]").expect("write"); if state.pop_front().unwrap() == State::Left { if i < self.tokens.len() - 1 { write!(f, ",").expect("write"); } state.push_front(State::Right); } } Token::Number(n) => { write!(f, "{}", n).expect("write"); if state.pop_front().unwrap() == State::Left { write!(f, ",").expect("write"); state.push_front(State::Right); } } } } assert!(state.is_empty()); Ok(()) } } impl SnailNum { fn magnitude(&self) -> usize { let mut tokens = self.tokens.clone(); while tokens.len() != 1 { let mut first_of_two_numbers: Option = None; for i in (0..tokens.len() - 2).rev() { if !tokens[i].is_num() || !tokens[i + 1].is_num() { continue; } first_of_two_numbers = Some(i); break; } let i = first_of_two_numbers.unwrap(); let mag = 3 * *tokens[i].as_num_mut() + 2 * *tokens[i + 1].as_num_mut(); tokens.splice(i - 1..=i + 2, [Token::Number(mag)]); } *tokens.first().unwrap().as_num() } fn add(mut self, mut other: SnailNum) -> SnailNum { let mut tokens = vec![]; tokens.push(Token::Start); tokens.append(&mut self.tokens); tokens.append(&mut other.tokens); tokens.push(Token::End); let mut new = SnailNum { tokens }; new.reduce(); new } fn reduce(&mut self) { loop { if self.try_explode() { continue; } if self.try_split() { continue; } break; } } fn try_explode(&mut self) -> bool { let mut depth = 0; let mut exploding_start_index: Option = None; for (i, t) in self.tokens.iter().enumerate() { if t == &Token::Start { depth += 1; if depth > 4 { exploding_start_index = Some(i); break; } } else if t == &Token::End { depth -= 1; } } if let Some(index) = exploding_start_index { let l = *self.tokens[index + 1].as_num_mut(); let r = *self.tokens[index + 2].as_num_mut(); let mut prev_num_index = Some(index - 1); let mut next_num_index = Some(index + 4); loop { if prev_num_index.is_none() || self.tokens[prev_num_index.unwrap()].is_num() { break; } prev_num_index = prev_num_index.unwrap().checked_sub(1); } loop { if self.tokens[next_num_index.unwrap()].is_num() { break; } let next = next_num_index.unwrap() + 1; if next >= self.tokens.len() { next_num_index = None; break; } else { next_num_index = Some(next); } } if let Some(i) = prev_num_index { *self.tokens[i].as_num_mut() += l; } if let Some(i) = next_num_index { *self.tokens[i].as_num_mut() += r; } self.tokens.splice(index..=index + 3, [Token::Number(0)]); true } else { false } } fn try_split(&mut self) -> bool { let mut index = 0; loop { if index >= self.tokens.len() { return false; } if let Token::Number(10..) = self.tokens[index] { break; } index += 1; } let old = *self.tokens[index].as_num_mut(); let half = (old as f64) / 2_f64; self.tokens.splice( index..=index, [ Token::Start, Token::Number(half.floor() as usize), Token::Number(half.ceil() as usize), Token::End, ], ); true } } // use std::cell::{Cell, Ref, RefCell}; // use std::collections::VecDeque; // use std::fmt::Display; // use std::iter::Peekable; // pub fn day18() { // assert_eq!( // SnailNum::from("[[1,2],3]"), // SnailNum { // left: NumOrSnail::Snail( // SnailNum { // left: NumOrSnail::Num(1.into()).into(), // right: NumOrSnail::Num(2.into()).into() // } // .into() // ) // .into(), // right: NumOrSnail::Num(3.into()).into(), // } // ); // assert_eq!( // SnailNum::from("[1,2]").add(SnailNum::from("[[3,4],5]")), // SnailNum { // left: NumOrSnail::Snail( // SnailNum { // left: NumOrSnail::Num(1.into()).into(), // right: NumOrSnail::Num(2.into()).into(), // } // .into() // ) // .into(), // right: NumOrSnail::Snail( // SnailNum { // left: NumOrSnail::Snail( // SnailNum { // left: NumOrSnail::Num(3.into()).into(), // right: NumOrSnail::Num(4.into()).into(), // } // .into() // ) // .into(), // right: NumOrSnail::Num(5.into()).into(), // } // .into() // ) // .into() // } // ); // let mut sn = SnailNum::from("[[6,[5,[4,[3,2]]]],1]"); // sn.reduce(); // println!("{}", sn); // } // fn parse_snail_num(s: &mut Peekable>) -> SnailNum { // assert_eq!(s.next(), Some('[')); // let left: NumOrSnail; // match s.peek() { // Some('[') => left = NumOrSnail::Snail(Box::new(parse_snail_num(s))), // Some(_) => left = NumOrSnail::Num(parse_num(s).into()), // None => panic!(), // } // assert_eq!(s.next(), Some(',')); // let right: NumOrSnail; // match s.peek() { // Some('[') => right = NumOrSnail::Snail(Box::new(parse_snail_num(s))), // Some(_) => right = NumOrSnail::Num(parse_num(s).into()), // None => panic!(), // } // assert_eq!(s.next(), Some(']')); // SnailNum { // left: left.into(), // right: right.into(), // } // } // fn parse_num(s: &mut Peekable>) -> usize { // let mut res = 0; // while let Some('0'..='9') = s.peek() { // let digit = s.next().unwrap().to_digit(10); // res *= 10; // res += digit.unwrap() as usize; // } // res // } // #[derive(Debug, PartialEq)] // struct SnailNum { // left: RefCell, // right: RefCell, // } // #[derive(Debug, PartialEq)] // enum NumOrSnail { // Num(Cell), // Snail(Box), // } // #[derive(Debug, Clone, Copy, PartialEq)] // enum Side { // Left, // Right, // } // impl SnailNum { // fn add(self, other: SnailNum) -> SnailNum { // SnailNum { // left: NumOrSnail::Snail(Box::new(self)).into(), // right: NumOrSnail::Snail(Box::new(other)).into(), // } // } // fn reduce(&mut self) { // loop { // if self.try_explode() { // continue; // } else if self.try_split() { // continue; // } else { // break; // } // } // } // fn try_explode(&mut self) -> bool { // let mut queue: VecDeque<(&SnailNum, Vec<(Ref<'_, &SnailNum>, Side)>, usize)> = // VecDeque::new(); // queue.push_back((self, vec![], 0)); // while let Some((item, mut parents, depth)) = queue.pop_front() { // if depth >= 4 { // let l = item.left.borrow().as_num(); // let r = item.right.borrow().as_num(); // // add item's right to next leaf to the right: // // go up until we're the left child then go back down to find the leftmost leaf of the right child // // and similarly for item's left to next leaf to the left // let mut immediate_parent: Option<(&SnailNum, Side)> = None; // let mut left_parent: Option<&SnailNum> = None; // let mut right_parent: Option<&SnailNum> = None; // while let Some((p, side)) = parents.pop() { // if immediate_parent.is_none() { // immediate_parent = Some((p, side)); // } // if left_parent.is_none() && side == Side::Left { // left_parent = Some(p); // } else if right_parent.is_none() && side == Side::Right { // right_parent = Some(p); // } // if left_parent.is_some() && right_parent.is_some() { // break; // } // } // if let Some(left_parent) = left_parent { // left_parent.right.borrow().add_to_leftmost_leaf(r); // } // if let Some(right_parent) = right_parent { // right_parent.left.borrow().add_to_rightmost_leaf(l); // } // // replace item with 0 // match immediate_parent.unwrap().1 { // Side::Left => { // *immediate_parent.unwrap().0.left.borrow_mut() = NumOrSnail::Num(0.into()); // } // Side::Right => { // *immediate_parent.unwrap().0.right.borrow_mut() = NumOrSnail::Num(0.into()); // } // } // return true; // } else { // // add right first so that left is at the front of the queue // let right_borrowed = item.right.borrow(); // if let Some(right) = right_borrowed.as_snail() { // let mut v = parents.clone(); // v.push((item, Side::Right)); // queue.push_front((right, v, depth + 1)); // } // // if let NumOrSnail::Snail(left) = &item.left { // // let mut v = parents.clone(); // // v.push((item, Side::Left)); // // queue.push_front((left.as_ref(), v, depth + 1)); // // } // } // } // false // } // fn add_to_leftmost_leaf(&self, amt: usize) { // self.left.borrow().add_to_leftmost_leaf(amt); // } // fn add_to_rightmost_leaf(&self, amt: usize) { // self.right.borrow().add_to_rightmost_leaf(amt); // } // fn try_split(&mut self) -> bool { // false // } // } // impl From<&str> for SnailNum { // fn from(s: &str) -> Self { // parse_snail_num(&mut s.chars().peekable()) // } // } // impl Display for SnailNum { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // write!(f, "[").expect("write"); // write!(f, "{}", self.left.borrow()).expect("write"); // write!(f, ",").expect("write"); // write!(f, "{}", self.right.borrow()).expect("write"); // write!(f, "]").expect("write"); // Ok(()) // } // } // impl NumOrSnail { // fn as_num(&self) -> usize { // match self { // NumOrSnail::Num(n) => n.get(), // _ => panic!(), // } // } // fn as_snail(&self) -> Option<&SnailNum> { // match self { // NumOrSnail::Snail(b) => Some(b), // _ => None, // } // } // fn add_to_leftmost_leaf(&self, amt: usize) { // match self { // NumOrSnail::Num(ref cur) => { // cur.set(cur.get() + amt); // } // NumOrSnail::Snail(child) => { // child.add_to_leftmost_leaf(amt); // } // } // } // fn add_to_rightmost_leaf(&self, amt: usize) { // match self { // NumOrSnail::Num(ref cur) => { // cur.set(cur.get() + amt); // } // NumOrSnail::Snail(child) => { // child.add_to_rightmost_leaf(amt); // } // } // } // } // impl Display for NumOrSnail { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // match self { // NumOrSnail::Num(n) => write!(f, "{}", n.get()), // NumOrSnail::Snail(snail) => write!(f, "{}", *snail), // } // } // }