193 lines
4.5 KiB
Rust
193 lines
4.5 KiB
Rust
use color_eyre::eyre;
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
enum Node {
|
|
Leaf(u8),
|
|
Branch {
|
|
left: Box<Node>,
|
|
right: Box<Node>,
|
|
}
|
|
}
|
|
use Node::*;
|
|
|
|
impl Node {
|
|
fn unwrap_branch(&self) -> (&Node, &Node) {
|
|
match self {
|
|
Node::Leaf(_) => panic!("Attempted to unwrap branches from a leaf node"),
|
|
Node::Branch {left, right} => (left, right),
|
|
}
|
|
}
|
|
|
|
fn leftmost_value_mut(&mut self) -> &mut u8 {
|
|
match self {
|
|
Node::Leaf(val) => val,
|
|
Node::Branch {left, ..} => left.leftmost_value_mut(),
|
|
}
|
|
}
|
|
|
|
fn rightmost_value_mut(&mut self) -> &mut u8 {
|
|
match self {
|
|
Node::Leaf(val) => val,
|
|
Node::Branch {right, ..} => right.rightmost_value_mut(),
|
|
}
|
|
}
|
|
|
|
fn magnitude(&self) -> usize {
|
|
match self {
|
|
Node::Leaf(v) => *v as usize,
|
|
Node::Branch {left, right} => 3 * left.magnitude() + 2 * right.magnitude(),
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct Parser<'a> {
|
|
chars: std::str::Chars<'a>,
|
|
}
|
|
|
|
impl<'a> Parser<'a> {
|
|
fn from(src: &'a str) -> Parser<'a> {
|
|
let mut chars = src.chars();
|
|
chars.next(); // throw away the opening bracket to avoid nesting too deeply
|
|
Parser {chars}
|
|
}
|
|
|
|
fn parse(&mut self) -> Node {
|
|
let mut left = None;
|
|
loop {
|
|
let node = match self.chars.next() {
|
|
Some('[') => self.parse(),
|
|
Some(','|']') => {continue;},
|
|
Some(c) => Node::Leaf(c.to_digit(10).unwrap() as u8),
|
|
None => {dbg!(left); panic!("Ran out of characters while parsing");},
|
|
};
|
|
|
|
if left.is_none() {
|
|
left = Some(node);
|
|
}
|
|
else {
|
|
return Node::Branch {
|
|
left: Box::new(left.unwrap()),
|
|
right: Box::new(node),
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn load(data: &str) -> Vec<Node> {
|
|
let mut nodes = Vec::new();
|
|
for line in data.lines() {
|
|
let mut parser = Parser::from(line);
|
|
nodes.push(parser.parse());
|
|
}
|
|
nodes
|
|
}
|
|
|
|
|
|
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 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 true;
|
|
},
|
|
Leaf(_) => return false,
|
|
Branch {left, right} => {
|
|
if split(left) {
|
|
return true;
|
|
}
|
|
else {
|
|
return split(right);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fn reduce(node: &mut Node) {
|
|
loop {
|
|
if let Some(..) = explode(node, 0) {
|
|
continue;
|
|
}
|
|
if split(node) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
fn add(left: Node, right: Node) -> Node {
|
|
let mut sum = Node::Branch {
|
|
left: Box::new(left),
|
|
right: Box::new(right),
|
|
};
|
|
reduce(&mut sum);
|
|
sum
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
// 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((one.magnitude(), max))
|
|
}
|