finish day 18
This commit is contained in:
parent
61374b8655
commit
8c6ffc2eb9
@ -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),
|
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 {
|
fn split(node: &mut Node) -> bool {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user