diff --git a/2021/input/2021/day18.txt b/2021/input/2021/day18.txt new file mode 100644 index 0000000..5116955 --- /dev/null +++ b/2021/input/2021/day18.txt @@ -0,0 +1,100 @@ +[[2,[2,[4,0]]],[6,1]] +[[3,[4,[2,4]]],[[6,9],[6,1]]] +[7,[8,[8,[0,8]]]] +[[[[2,9],5],5],[[[0,1],8],[[7,9],5]]] +[[[[3,0],[7,0]],[[9,6],[1,9]]],4] +[[[0,[4,8]],8],[[[2,1],9],6]] +[[[5,[7,7]],[[9,6],2]],[[[5,8],8],0]] +[[0,3],[[8,2],[6,[2,2]]]] +[[[9,0],[4,[4,7]]],[7,[[9,1],9]]] +[0,[7,[1,1]]] +[[[4,[0,1]],[[1,0],8]],[[[3,9],[0,1]],[[9,1],[8,8]]]] +[[[6,0],3],2] +[[[[4,1],[2,7]],[9,[8,9]]],[[3,0],0]] +[[[[2,4],[8,7]],[9,[9,7]]],[[[2,5],6],9]] +[[7,6],[[4,[2,4]],[3,8]]] +[[7,2],[[8,8],7]] +[[[[6,0],4],[[4,7],4]],[[6,[2,7]],[[6,5],3]]] +[[[[8,8],[7,6]],4],5] +[[0,[[6,9],[7,9]]],[9,5]] +[9,[[[0,4],6],[[7,0],0]]] +[[[[4,4],0],[3,[3,9]]],[[7,5],[5,[7,2]]]] +[[[8,3],[[8,5],[4,4]]],[0,[0,3]]] +[[9,[3,[6,7]]],[[7,0],[[9,2],7]]] +[[[3,7],[[3,6],9]],7] +[[2,[2,[5,7]]],[[[6,4],5],[4,7]]] +[[[[9,0],2],[[4,4],6]],[[[3,2],[5,5]],[[5,9],7]]] +[[[[2,5],4],[8,5]],6] +[[[3,2],[[1,7],5]],[[8,1],[1,[1,2]]]] +[8,[[3,[5,4]],5]] +[[[2,[5,9]],[1,3]],[[[2,3],[8,3]],[[5,1],[8,9]]]] +[[[2,0],[[3,3],[4,7]]],[[[8,7],[7,4]],1]] +[[[[7,4],9],[3,[4,1]]],[[[8,4],5],7]] +[[[[0,2],9],3],[9,[5,3]]] +[3,4] +[[[1,[0,2]],[[9,9],[8,2]]],6] +[[[[2,9],[3,5]],9],[[9,3],[3,[6,7]]]] +[[0,[[4,6],4]],[2,[5,2]]] +[9,[[9,[6,8]],8]] +[3,[[[1,2],[0,9]],[[4,9],1]]] +[[[[8,7],[1,7]],[[2,6],[8,5]]],[3,[[8,0],[6,9]]]] +[[8,[[4,9],7]],[3,[9,4]]] +[[0,[[3,2],[2,2]]],0] +[[[2,7],[[5,7],4]],[[[6,0],[2,1]],[[4,1],[1,6]]]] +[[[[9,6],[0,3]],[[0,6],[0,4]]],[[[3,7],[6,7]],7]] +[[[[1,1],6],[[5,6],4]],[[5,[0,7]],1]] +[[[3,9],[[7,3],[1,5]]],[[[1,2],3],[0,[5,6]]]] +[[[[4,4],[0,5]],6],[[7,[2,0]],6]] +[[[[2,2],6],9],[[[9,1],2],[[8,6],8]]] +[[[[5,0],8],[[5,7],7]],[6,[5,3]]] +[[[[8,2],[8,4]],1],[[1,[7,3]],8]] +[[[[3,2],2],[[4,9],[5,4]]],[[[9,2],4],[5,[6,0]]]] +[[1,[[0,6],0]],[[[1,5],2],[[6,0],[3,7]]]] +[4,[7,[6,[3,3]]]] +[[[0,[2,5]],2],5] +[[[0,[5,7]],9],[[[2,3],[3,4]],[[0,4],9]]] +[[3,1],[[[4,1],9],[[0,5],[8,6]]]] +[[9,[2,0]],[[0,[1,7]],[9,[6,4]]]] +[[[[6,5],5],5],[5,8]] +[[[[2,8],[1,3]],[[5,4],2]],[[[0,8],[5,1]],[9,[5,6]]]] +[[[[6,9],7],[9,7]],2] +[[[[1,7],8],[8,7]],[[[3,5],4],8]] +[[[[1,8],[1,0]],0],[[7,1],5]] +[[[9,[6,8]],3],[[5,1],[4,[8,2]]]] +[[[0,[2,1]],1],[3,[9,[5,5]]]] +[[2,5],[2,5]] +[[[[1,1],[8,3]],[[1,9],[4,9]]],[[5,[4,8]],[[5,0],0]]] +[[[0,7],[[3,4],1]],[[[1,2],[2,9]],[[2,0],9]]] +[3,2] +[[[9,[8,2]],[7,3]],7] +[[[[6,9],9],[3,2]],0] +[[3,[[6,1],8]],6] +[[[[5,9],9],[[4,4],7]],[7,5]] +[1,[[2,8],0]] +[[2,[0,6]],[[[3,3],[0,4]],8]] +[[[[4,8],9],[0,[3,0]]],[[0,[3,1]],[8,[7,4]]]] +[[[6,[8,0]],[0,[8,9]]],[3,8]] +[[[[0,8],[9,4]],[1,[2,0]]],1] +[[7,6],[[[0,2],9],3]] +[[[[1,0],3],2],1] +[[[[1,2],8],5],7] +[0,[[3,0],7]] +[[7,[[0,9],[8,4]]],[[2,0],[[2,8],1]]] +[[[1,8],[[8,1],1]],[3,[8,9]]] +[4,[[3,7],[[5,2],9]]] +[[[[3,8],[2,9]],[3,9]],[[[3,7],[6,9]],[[1,7],2]]] +[9,[[[3,7],9],[[4,9],[8,6]]]] +[[7,[3,9]],[0,7]] +[[[1,6],0],[[7,[8,1]],[6,3]]] +[[[[3,9],3],[[2,6],[8,0]]],[[3,3],9]] +[[[1,2],[1,6]],[[1,[4,2]],0]] +[[[0,[3,0]],2],[[7,[9,4]],[6,8]]] +[6,[[[3,1],1],5]] +[[[3,4],[[5,9],[1,1]]],[[2,[0,1]],3]] +[[2,[[1,5],7]],[0,2]] +[[1,[[6,7],7]],4] +[6,[5,[[3,2],[6,8]]]] +[[[3,9],[[4,0],6]],[8,[3,[5,2]]]] +[[5,[[7,3],[2,2]]],[[7,7],7]] +[[[1,2],[[2,4],[6,1]]],[[0,[4,2]],[[5,7],[2,3]]]] +[[[8,7],8],[[7,[3,6]],[[1,0],4]]] diff --git a/2021/src/day18.rs b/2021/src/day18.rs new file mode 100644 index 0000000..f248f1e --- /dev/null +++ b/2021/src/day18.rs @@ -0,0 +1,232 @@ +use advent::prelude::*; +use aoc_runner_derive::{aoc, aoc_generator}; +use std::io::Read; + +#[derive(Debug, PartialEq)] +enum ChildType { + None, + Value(usize), + Subtree(Idx), +} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +struct Idx(usize); + +#[derive(Debug, PartialEq)] +struct Node { + idx: Idx, + parent: Option, + left: ChildType, + right: ChildType, +} +// Tree needs to support merging two into one for adding snailfish numbers. +// Tree needs to support rightward and leftward depth first searches to find neighbors for applying +// exploded spill over. +// Need to support remove and/or replace for explode. +// Need to support insert and/or replace for split. +#[derive(Debug, Default, PartialEq)] +struct Tree { + root: Idx, + nodes: Vec, +} + +fn read_byte(reader: &mut R) -> std::io::Result> { + reader.bytes().next().transpose() +} + +impl Tree { + fn find_root(&self, node: &Node) -> Idx { + match node.parent { + Some(parent_idx) => self.find_root(&self[parent_idx]), + None => node.idx, + } + } + fn add_node(&mut self, left: ChildType, right: ChildType) -> Idx { + let idx = Idx(self.nodes.len()); + self.nodes.push(Node { + idx, + parent: None, + left, + right, + }); + idx + } + + fn from_str_node(&mut self, r: &mut R) -> ChildType { + let mut parsing_left = true; + // Can this be rewritten to eliminate the need for `None`? + let mut left = ChildType::None; + let mut right = ChildType::None; + while let Ok(Some(b)) = read_byte(r) { + match b { + b'[' => { + let node = self.from_str_node(r); + if parsing_left { + left = node; + } else { + right = node; + } + } + b']' => { + let mut left_idx = None; + let mut right_idx = None; + if let ChildType::Subtree(idx) = left { + left_idx = Some(idx); + } + if let ChildType::Subtree(idx) = right { + right_idx = Some(idx); + } + let child_idx = self.add_node(left, right); + if let Some(idx) = left_idx { + self[idx].parent = Some(child_idx); + } + if let Some(idx) = right_idx { + self[idx].parent = Some(child_idx); + } + return ChildType::Subtree(child_idx); + } + b',' => parsing_left = false, + b'0'..=b'9' => { + let v = dbg!(b - b'0'); + if parsing_left { + left = ChildType::Value(v.into()); + parsing_left = false; + } else { + right = ChildType::Value(v.into()); + } + continue; + } + _ => panic!("unknown byte '{}'", b), + } + } + unreachable!() + } + + fn fmt_node(&self, f: &mut Formatter<'_>, node: &Node) -> std::fmt::Result { + write!(f, "[")?; + match node.left { + ChildType::None => panic!("left node was None"), + ChildType::Value(v) => write!(f, "{}", v), + ChildType::Subtree(idx) => self.fmt_node(f, &self[idx]), + }; + write!(f, ",")?; + match node.right { + ChildType::None => panic!("right node was None"), + ChildType::Value(v) => write!(f, "{}", v), + ChildType::Subtree(idx) => self.fmt_node(f, &self[idx]), + }; + write!(f, "]")?; + Ok(()) + } +} + +impl FromStr for Tree { + type Err = Infallible; + + fn from_str(input: &str) -> std::result::Result { + let mut tree = Tree::default(); + let mut bytes = input.as_bytes(); + assert_eq!( + read_byte(&mut bytes).expect("couldn't read first byte"), + Some(b'[') + ); + tree.from_str_node(&mut bytes); + tree.root = tree.find_root(&tree[Idx(0)]); + Ok(tree) + } +} + +impl Index for Tree { + type Output = Node; + fn index(&self, idx: Idx) -> &Self::Output { + &self.nodes[idx.0] + } +} + +impl IndexMut for Tree { + fn index_mut(&mut self, idx: Idx) -> &mut Self::Output { + &mut self.nodes[idx.0] + } +} + +impl Display for Tree { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.nodes.is_empty() { + return write!(f, "[]"); + } + + let node = &self[self.root]; + self.fmt_node(f, &node)?; + Ok(()) + } +} + +#[aoc(day18, part1)] +fn part1(input: &str) -> Result { + for l in input.lines() { + let tree: Tree = l.parse()?; + dbg!(&tree); + } + Ok(0) +} + +/* +#[aoc(day18, part2)] +fn part2(input: &str) -> Result { +todo!("part2"); +Ok(0) +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_display() -> Result<()> { + for (i, s) in ["[1,2]", "[[1,2],3]", "[1,[2,3]]", "[[1,2],[3,4]]"] + .into_iter() + .enumerate() + { + let t = s.parse::()?; + assert_eq!(&t.to_string(), s, "input {}: '{}'", i, s); + //assert_eq!(&t.to_string(), s, "input {}: '{}'\ntree: {:#?}", i, s, t); + } + Ok(()) + } + + //#[test] + fn test_part1() -> Result<()> { + let sum = [ + [[[6, 6], [7, 6]], [[7, 7], [7, 0]]], + [[[7, 7], [7, 7]], [[7, 8], [9, 9]]], + ]; + dbg!(&sum); + let input = r#" +[[[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]]] + "# + .trim(); + assert_eq!(part1(input)?, 4140); + Ok(()) + } + + /* + #[test] + fn test_part2()->Result<()> { + let input = r#" + "# + .trim(); + assert_eq!(part2(input)?, usize::MAX); + Ok(()) + } + */ +} diff --git a/2021/src/lib.rs b/2021/src/lib.rs index 86cbda1..e63a17c 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -7,6 +7,7 @@ pub mod day13; pub mod day15; pub mod day16; pub mod day17; +pub mod day18; pub mod day2; pub mod day3; pub mod day4;