finish day 18

This commit is contained in:
Joseph Montanaro 2022-01-08 19:50:46 -08:00
parent 61374b8655
commit 8c6ffc2eb9

View File

@ -1,7 +1,7 @@
use color_eyre::eyre; use color_eyre::eyre;
#[derive(Debug)] #[derive(Debug, Clone)]
enum Node { enum Node {
Leaf(u8), Leaf(u8),
Branch { Branch {
@ -9,36 +9,9 @@ enum Node {
right: Box<Node>, right: Box<Node>,
} }
} }
use Node::*;
impl Node { impl Node {
fn is_leaf(&self) -> bool {
match self {
Node::Leaf(_) => true,
Node::Branch {..} => false,
}
}
fn is_branch(&self) -> bool {
match self {
Node::Leaf(_) => false,
Node::Branch {..} => true,
}
}
fn unwrap_value(&self) -> u8 {
match self {
Node::Leaf(v) => *v,
Node::Branch {..} => panic!("Attempted to unwrap value from a branch node"),
}
}
fn value_mut(&mut self) -> &mut u8 {
match self {
Node::Leaf(v) => v,
Node::Branch {..} => panic!("Attempted to unwrap value from a branch node"),
}
}
fn unwrap_branch(&self) -> (&Node, &Node) { fn unwrap_branch(&self) -> (&Node, &Node) {
match self { match self {
Node::Leaf(_) => panic!("Attempted to unwrap branches from a leaf node"), Node::Leaf(_) => panic!("Attempted to unwrap branches from a leaf node"),
@ -113,71 +86,76 @@ fn load(data: &str) -> Vec<Node> {
} }
#[derive(Debug)] fn explode(node: &mut Node, depth: usize) -> Option<(u8, u8)> {
enum ReduceOp { // only branch nodes can explode
Noop, if let Leaf(_) = node {return None;}
Split,
Explode(u8, u8),
}
fn walk(node: &mut Node, depth: usize) -> ReduceOp {
// just to improve readability
use {Node::*, ReduceOp::*};
if depth >= 4 { if depth >= 4 {
if let Branch {left, right} = node { let (left, right) = node.unwrap_branch();
let v1 = left.unwrap_value(); match (left, right) {
let v2 = right.unwrap_value(); (Leaf(v1), Leaf(v2)) => {
*node = Leaf(0); let result = (*v1, *v2);
return Explode(v1, v2); *node = Leaf(0);
return Some(result);
},
_ => (),
} }
} }
if let Branch {left, right} = node {
if let Some((v1, v2)) = explode(left, depth + 1) {
if v2 > 0 {
*right.leftmost_value_mut() += v2;
return Some((v1, 0));
}
return Some((v1, v2));
}
if let Some((v1, v2)) = explode(right, depth + 1) {
if v1 > 0 {
*left.rightmost_value_mut() += v1;
return Some((0, v2));
}
return Some((v1, v2));
}
}
return None;
}
fn split(node: &mut Node) -> bool {
match node { match node {
Leaf(v) if *v > 9 => { Leaf(v) if *v > 9 => {
*node = Branch { *node = Branch {
left: Box::new(Leaf(*v / 2)), left: Box::new(Leaf(*v / 2)),
right: Box::new(Leaf((*v + 1) / 2)), right: Box::new(Leaf((*v + 1) / 2)),
}; };
return Split return true;
}, },
Leaf(_) => return Noop, Leaf(_) => return false,
// here's where it gets complicated
Branch {left, right} => { Branch {left, right} => {
// keep walking, depth-first and left-first if split(left) {
let res = walk(left, depth + 1); return true;
// if a sub-node exploded, and our right node is a leaf, add the right half of the explode to our right leaf
match res {
Explode(v1, v2) if v2 > 0 => {
*right.leftmost_value_mut() += v2;
// and propagate the explode up again, except we've already used v2 so replace it with 0
return Explode(v1, 0);
},
Explode(..)|Split => return res,
Noop => (),
} }
else {
// if no children of the left branch exploded, keep going with the right return split(right);
let res = walk(right, depth + 1);
// same concept, except we're adding the left half of the sub-explode to our left leaf (if it is a leaf)
match res {
Explode(v1, v2) if v1 > 0 => {
*left.rightmost_value_mut() += v1;
return Explode(0, v2);
},
Explode(..)|Split => return res,
Noop => (),
} }
} }
} }
// if everything else completes, then there were no splits or explodes below us in the tree
return Noop
} }
fn reduce(node: &mut Node) { fn reduce(node: &mut Node) {
while let ReduceOp::Explode(..)|ReduceOp::Split = walk(node, 0) {} loop {
if let Some(..) = explode(node, 0) {
continue;
}
if split(node) {
continue;
}
break;
}
} }
@ -191,22 +169,24 @@ fn add(left: Node, right: Node) -> Node {
} }
const SAMPLE: &str = "[[1,2],[[3,4],5]] pub fn run(data: &str) -> eyre::Result<(usize, usize)> {
[[[[0,7],4],[[7,8],[6,0]]],[8,1]] let nodes = load(data);
[[[[1,1],[2,2]],[3,3]],[4,4]] let one = nodes.into_iter().reduce(|sum, next| add(sum, next)).unwrap();
[[[[3,0],[5,3]],[4,4]],[5,5]]
[[[[5,0],[7,4]],[5,5]],[6,6]]
[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]";
pub fn run(_data: &str) -> eyre::Result<(usize, usize)> { // I'm sure there's a more efficient way to do this, but
let nodes = load(SAMPLE); let mut max = 0;
let nodes2 = load(data);
// let one = nodes.into_iter().reduce(|sum, next| add(sum, next)); for i in 0..nodes2.len() {
// dbg!(one); for j in 0..nodes2.len() {
if i == j {continue;}
for node in nodes { let a = nodes2[i].clone();
println!("{}", node.magnitude()); let b = nodes2[j].clone();
let magnitude = add(a, b).magnitude();
if magnitude > max {
max = magnitude;
}
}
} }
Ok((0, 0)) Ok((one.magnitude(), max))
} }