completely rework day 18
This commit is contained in:
parent
54053779aa
commit
61374b8655
@ -1,90 +1,212 @@
|
|||||||
// use std::iter::Peekable;
|
|
||||||
use std::str::Chars;
|
|
||||||
|
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Item {
|
enum Node {
|
||||||
Value(u8),
|
Leaf(u8),
|
||||||
SubPair(Box<Pair>),
|
Branch {
|
||||||
}
|
left: Box<Node>,
|
||||||
|
right: Box<Node>,
|
||||||
impl Item {
|
|
||||||
fn magnitude(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Item::Value(v) => *v as usize,
|
|
||||||
Item::SubPair(pair) => pair.magnitude(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Node {
|
||||||
struct Pair {
|
fn is_leaf(&self) -> bool {
|
||||||
left: Item,
|
match self {
|
||||||
right: Item,
|
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"),
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Pair {
|
|
||||||
fn magnitude(&self) -> usize {
|
fn magnitude(&self) -> usize {
|
||||||
3 * self.left.magnitude() + 2 * self.right.magnitude()
|
match self {
|
||||||
|
Node::Leaf(v) => *v as usize,
|
||||||
|
Node::Branch {left, right} => 3 * left.magnitude() + 2 * right.magnitude(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
chars: Chars<'a>,
|
chars: std::str::Chars<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
fn from(src: &'a str) -> Parser<'a> {
|
fn from(src: &'a str) -> Parser<'a> {
|
||||||
let mut chars = src.chars();
|
let mut chars = src.chars();
|
||||||
chars.next(); // throw away the opening bracket so we don't nest too deeply
|
chars.next(); // throw away the opening bracket to avoid nesting too deeply
|
||||||
Parser {chars}
|
Parser {chars}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(&mut self) -> eyre::Result<Pair> {
|
fn parse(&mut self) -> Node {
|
||||||
let mut items = Vec::with_capacity(2);
|
let mut left = None;
|
||||||
while items.len() < 2 {
|
loop {
|
||||||
let item = match self.chars.next() {
|
let node = match self.chars.next() {
|
||||||
Some('[') => Item::SubPair(Box::new(self.parse()?)),
|
Some('[') => self.parse(),
|
||||||
Some(','|']') => {continue;},
|
Some(','|']') => {continue;},
|
||||||
Some(c) => Item::Value(c.to_digit(10).unwrap() as u8),
|
Some(c) => Node::Leaf(c.to_digit(10).unwrap() as u8),
|
||||||
None => {return Err(eyre!("Ran out of characters to parse"));},
|
None => {dbg!(left); panic!("Ran out of characters while parsing");},
|
||||||
};
|
};
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
let right = items.pop().unwrap();
|
if left.is_none() {
|
||||||
let left = items.pop().unwrap();
|
left = Some(node);
|
||||||
Ok(Pair {left, right})
|
}
|
||||||
|
else {
|
||||||
|
return Node::Branch {
|
||||||
|
left: Box::new(left.unwrap()),
|
||||||
|
right: Box::new(node),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load(data: &str) -> Vec<Node> {
|
||||||
fn load(data: &str) -> eyre::Result<Vec<Pair>>{
|
let mut nodes = Vec::new();
|
||||||
let mut pairs = Vec::new();
|
|
||||||
for line in data.lines() {
|
for line in data.lines() {
|
||||||
let mut parser = Parser::from(line);
|
let mut parser = Parser::from(line);
|
||||||
let pair = parser.parse()
|
nodes.push(parser.parse());
|
||||||
.map_err(|_| eyre!("Invalid input: {}", line))?;
|
|
||||||
pairs.push(pair);
|
|
||||||
}
|
}
|
||||||
Ok(pairs)
|
nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const _SAMPLE: &str = "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]";
|
#[derive(Debug)]
|
||||||
|
enum ReduceOp {
|
||||||
|
Noop,
|
||||||
|
Split,
|
||||||
|
Explode(u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(data: &str) -> eyre::Result<(usize, usize)> {
|
|
||||||
// let pairs = load(data)?;
|
|
||||||
// dbg!(pairs.len());
|
|
||||||
// dbg!(&pairs[0]);
|
|
||||||
|
|
||||||
let mut parser = Parser::from(_SAMPLE);
|
fn walk(node: &mut Node, depth: usize) -> ReduceOp {
|
||||||
let root = parser.parse()?;
|
// just to improve readability
|
||||||
dbg!(root.magnitude());
|
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 {
|
||||||
|
Leaf(v) if *v > 9 => {
|
||||||
|
*node = Branch {
|
||||||
|
left: Box::new(Leaf(*v / 2)),
|
||||||
|
right: Box::new(Leaf((*v + 1) / 2)),
|
||||||
|
};
|
||||||
|
return Split
|
||||||
|
},
|
||||||
|
Leaf(_) => return Noop,
|
||||||
|
// here's where it gets complicated
|
||||||
|
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 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 => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn add(left: Node, right: Node) -> Node {
|
||||||
|
let mut sum = Node::Branch {
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
reduce(&mut sum);
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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(SAMPLE);
|
||||||
|
|
||||||
|
// let one = nodes.into_iter().reduce(|sum, next| add(sum, next));
|
||||||
|
// dbg!(one);
|
||||||
|
|
||||||
|
for node in nodes {
|
||||||
|
println!("{}", node.magnitude());
|
||||||
|
}
|
||||||
|
|
||||||
Ok((0, 0))
|
Ok((0, 0))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user