finish day 18
This commit is contained in:
parent
61374b8655
commit
8c6ffc2eb9
@ -1,7 +1,7 @@
|
||||
use color_eyre::eyre;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum Node {
|
||||
Leaf(u8),
|
||||
Branch {
|
||||
@ -9,36 +9,9 @@ enum Node {
|
||||
right: Box<Node>,
|
||||
}
|
||||
}
|
||||
use 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) {
|
||||
match self {
|
||||
Node::Leaf(_) => panic!("Attempted to unwrap branches from a leaf node"),
|
||||
@ -113,71 +86,76 @@ fn load(data: &str) -> Vec<Node> {
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ReduceOp {
|
||||
Noop,
|
||||
Split,
|
||||
Explode(u8, u8),
|
||||
fn explode(node: &mut Node, depth: usize) -> Option<(u8, u8)> {
|
||||
// only branch nodes can explode
|
||||
if let Leaf(_) = node {return None;}
|
||||
|
||||
if depth >= 4 {
|
||||
let (left, right) = node.unwrap_branch();
|
||||
match (left, right) {
|
||||
(Leaf(v1), Leaf(v2)) => {
|
||||
let result = (*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 walk(node: &mut Node, depth: usize) -> ReduceOp {
|
||||
// just to improve readability
|
||||
use {Node::*, ReduceOp::*};
|
||||
|
||||
if depth >= 4 {
|
||||
if let Branch {left, right} = node {
|
||||
let v1 = left.unwrap_value();
|
||||
let v2 = right.unwrap_value();
|
||||
*node = Leaf(0);
|
||||
return Explode(v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
fn split(node: &mut Node) -> bool {
|
||||
match node {
|
||||
Leaf(v) if *v > 9 => {
|
||||
*node = Branch {
|
||||
left: Box::new(Leaf(*v / 2)),
|
||||
right: Box::new(Leaf((*v + 1) / 2)),
|
||||
};
|
||||
return Split
|
||||
return true;
|
||||
},
|
||||
Leaf(_) => return Noop,
|
||||
// here's where it gets complicated
|
||||
Leaf(_) => return false,
|
||||
Branch {left, right} => {
|
||||
// keep walking, depth-first and left-first
|
||||
let res = walk(left, depth + 1);
|
||||
// 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 => (),
|
||||
if split(left) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if no children of the left branch exploded, keep going with the 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 => (),
|
||||
else {
|
||||
return split(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if everything else completes, then there were no splits or explodes below us in the tree
|
||||
return Noop
|
||||
}
|
||||
|
||||
|
||||
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]]
|
||||
[[[[0,7],4],[[7,8],[6,0]]],[8,1]]
|
||||
[[[[1,1],[2,2]],[3,3]],[4,4]]
|
||||
[[[[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)> {
|
||||
let nodes = load(data);
|
||||
let one = nodes.into_iter().reduce(|sum, next| add(sum, next)).unwrap();
|
||||
|
||||
pub fn run(_data: &str) -> eyre::Result<(usize, usize)> {
|
||||
let nodes = load(SAMPLE);
|
||||
|
||||
// let one = nodes.into_iter().reduce(|sum, next| add(sum, next));
|
||||
// dbg!(one);
|
||||
|
||||
for node in nodes {
|
||||
println!("{}", node.magnitude());
|
||||
// I'm sure there's a more efficient way to do this, but
|
||||
let mut max = 0;
|
||||
let nodes2 = load(data);
|
||||
for i in 0..nodes2.len() {
|
||||
for j in 0..nodes2.len() {
|
||||
if i == j {continue;}
|
||||
let a = nodes2[i].clone();
|
||||
let b = nodes2[j].clone();
|
||||
let magnitude = add(a, b).magnitude();
|
||||
if magnitude > max {
|
||||
max = magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((0, 0))
|
||||
Ok((one.magnitude(), max))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user