Add day 18 parsing + exploding

This commit is contained in:
kageru 2021-12-18 16:18:25 +01:00
parent 79ab35a23e
commit 35e85c9737
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
3 changed files with 281 additions and 0 deletions

View File

@ -8,6 +8,7 @@ fnv = "1.0.7"
impl_ops = "0.1.1"
itertools = "0.10"
paste = "1.0"
test-case = "1.2.1"
[profile.bench]
lto = true

100
2021/inputs/day18 Normal file
View File

@ -0,0 +1,100 @@
[4,[3,[9,[9,0]]]]
[[[7,6],[2,[2,5]]],[5,[[7,3],8]]]
[4,[4,6]]
[[0,[5,6]],[[[1,3],[2,7]],[[0,6],4]]]
[6,[[3,[6,0]],3]]
[[7,[9,[8,5]]],[6,7]]
[[[[2,6],1],2],[3,[8,4]]]
[4,[[[5,4],[2,7]],[[8,0],[2,3]]]]
[[[[4,3],2],[[3,6],[2,5]]],[[[3,7],8],0]]
[[[8,[0,7]],1],[[9,[3,9]],9]]
[[[[3,0],[1,3]],[[0,9],8]],[[[7,2],9],[[1,4],[3,5]]]]
[[[[9,6],[4,4]],[1,3]],[[4,3],[[6,4],[8,4]]]]
[[[1,2],[[7,6],[2,3]]],[[4,6],[4,2]]]
[[[4,8],[[5,8],1]],[2,3]]
[[[5,2],[3,[5,7]]],[[2,9],5]]
[[[6,[3,2]],[2,6]],[[8,[4,2]],[[5,2],7]]]
[[[[2,6],[0,1]],[7,[3,6]]],[[1,6],[[7,9],0]]]
[[[0,3],[8,1]],[[[9,0],3],[0,2]]]
[[8,[[7,1],[4,7]]],[[0,[1,3]],[8,2]]]
[[[[2,3],4],[[0,8],[9,0]]],[1,[[5,3],4]]]
[[[[7,2],2],[[1,3],[8,3]]],[4,[[7,9],[0,6]]]]
[[[[2,2],[3,4]],[[1,5],[4,3]]],[6,[[7,2],1]]]
[1,[[[5,7],0],[9,[8,8]]]]
[[[[9,2],[0,9]],[4,[7,8]]],[[4,8],[[1,8],[4,9]]]]
[[[[4,7],2],2],4]
[1,[[2,[4,2]],1]]
[[[[7,2],[3,8]],[0,[1,3]]],[[[4,4],[2,4]],[8,2]]]
[[[[1,0],[0,5]],2],[[9,[5,0]],[[1,6],5]]]
[4,[[[8,1],[1,4]],[7,[1,3]]]]
[[[6,[0,4]],[[4,6],[2,4]]],[9,[1,5]]]
[[[[3,6],[3,3]],1],[0,[[8,8],2]]]
[[7,[5,[2,6]]],[[[7,9],6],[0,[3,6]]]]
[[[[6,7],4],[[2,9],2]],3]
[[[7,[1,7]],[5,4]],[[[1,1],[0,1]],5]]
[[6,[[1,0],6]],[0,[6,[0,5]]]]
[[[[2,4],[4,6]],9],[4,[[8,0],7]]]
[[[[9,9],[5,7]],[9,[8,6]]],[[3,[2,3]],0]]
[[0,[1,[5,3]]],[3,[8,[3,4]]]]
[[[[4,3],8],[2,9]],[[1,[6,5]],[[5,7],2]]]
[[[0,[7,4]],[9,[9,6]]],[[8,[5,5]],[[6,4],1]]]
[[[[7,3],[7,9]],[8,[6,2]]],[[8,[4,5]],[[6,4],[6,7]]]]
[[7,[[9,0],[9,0]]],[[[0,8],2],[8,[8,3]]]]
[4,[7,[5,6]]]
[7,[[[3,8],8],3]]
[[[4,[6,6]],0],[9,0]]
[[[[7,4],8],8],[[0,1],[[0,0],[2,4]]]]
[7,[1,[[9,4],[3,6]]]]
[[[[2,8],9],[[8,6],[2,2]]],[[[5,1],9],[2,[0,7]]]]
[8,7]
[[[[0,8],4],[[9,9],[9,9]]],[[[4,3],[1,0]],[6,8]]]
[[[[8,3],[8,9]],1],[[4,[1,0]],[[4,0],[2,3]]]]
[[[[4,7],[1,3]],[6,9]],[[1,0],[[1,8],5]]]
[[2,[4,[6,5]]],[3,[[9,9],5]]]
[[[[7,6],4],9],[8,[4,5]]]
[[[0,[6,6]],[7,[8,9]]],[[[0,0],[3,4]],[4,[1,8]]]]
[[[9,[7,0]],[5,8]],[6,[[5,0],[0,6]]]]
[[[[4,0],[1,9]],[7,[3,6]]],[[2,[8,6]],[[2,8],[8,2]]]]
[[[9,6],8],[[[5,5],[4,8]],0]]
[[[[1,7],1],2],[[[6,8],3],[[3,3],5]]]
[3,[5,[[3,8],6]]]
[3,[[[9,6],[5,8]],[9,2]]]
[[6,1],[6,4]]
[[2,6],[[[1,2],2],8]]
[[[[1,7],[3,6]],[2,[0,2]]],[[3,0],9]]
[1,[[0,[4,9]],5]]
[[[[5,5],[5,2]],[0,[6,4]]],8]
[0,[7,[[6,9],[6,0]]]]
[[[[2,2],[4,7]],[[7,4],6]],[[0,[1,7]],[[3,2],6]]]
[[9,8],0]
[[[[5,4],[4,8]],2],[3,[8,9]]]
[[[[7,0],8],5],[2,6]]
[[[5,[0,8]],5],[[[5,0],[1,8]],[[0,2],7]]]
[[[[9,4],8],[[6,5],4]],[[5,[8,9]],[4,[0,4]]]]
[[[[3,6],7],[[9,3],7]],[7,[[8,3],9]]]
[[[[0,7],5],[[5,7],2]],[[2,[9,5]],[[7,7],[5,0]]]]
[[[[7,5],2],[8,6]],[[2,[6,2]],[5,[3,1]]]]
[[9,[9,1]],6]
[[[0,7],[[5,9],2]],3]
[[[9,3],[8,8]],[0,[4,5]]]
[[[[6,2],5],[4,[3,1]]],[9,[2,8]]]
[[[1,[9,4]],[[0,0],2]],[[1,[2,1]],[[7,8],[3,2]]]]
[[[[0,6],[8,9]],[[4,7],[5,6]]],[[[1,4],[8,7]],[4,6]]]
[[[[6,4],[1,5]],[0,8]],[[[9,7],[1,2]],[9,4]]]
[[[[4,5],[0,7]],[9,[1,8]]],[[[5,0],6],7]]
[[[0,[6,9]],[5,[5,6]]],7]
[[4,5],[[7,[6,5]],1]]
[[[7,9],[6,7]],[4,1]]
[[[[9,6],1],[[3,1],[9,7]]],[1,[7,1]]]
[[[0,[2,0]],5],[[8,[7,6]],[[7,3],4]]]
[[[6,[1,7]],[9,[2,7]]],3]
[[[6,[8,2]],5],[4,[[1,3],[5,1]]]]
[[[4,[3,3]],[4,[2,4]]],[5,4]]
[[[1,6],[4,[4,0]]],[[8,[2,2]],[[8,1],[4,7]]]]
[[2,0],[[2,1],[[4,8],[2,7]]]]
[9,[[8,4],0]]
[[1,6],[[5,[1,3]],[9,[0,9]]]]
[[[0,[3,5]],3],[[2,[8,0]],[[2,0],[4,3]]]]
[[[1,[1,9]],[9,[7,9]]],[[2,2],[[6,7],[0,7]]]]
[[[4,6],[[6,2],[0,9]]],[[1,0],[1,[6,7]]]]
[9,[[[0,1],4],[[9,3],3]]]

180
2021/src/bin/day18.rs Normal file
View File

@ -0,0 +1,180 @@
#![feature(box_syntax)]
#![feature(test)]
extern crate test;
use aoc2021::common::*;
use std::{fmt, ops::Add};
const DAY: usize = 18;
type Parsed = Vec<Node>;
#[derive(Debug, PartialEq)]
enum Node {
Number(usize),
Pair(Box<(Node, Node)>),
}
impl Add for Node {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Node::Pair(box (self, rhs))
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Node::Number(n) => write!(f, "{n}"),
Node::Pair(p) => write!(f, "[{},{}]", p.0, p.1),
}
}
}
fn parse_input(raw: &str) -> Parsed {
raw.lines().map(|l| parse_node(l).0).collect()
}
fn parse_node(raw: &str) -> (Node, usize) {
if let Some(inner) = raw.strip_prefix('[') {
let (first, offset) = parse_node(inner);
let (second, offset2) = parse_node(&inner[offset..]);
(Node::Pair(box (first, second)), 1 /* the opening [ */ + offset + offset2 + 1 /* the comma */)
} else {
let n = raw.as_bytes()[0] - b'0';
debug_assert!(n <= 9, "Number was {n}, raw was {raw}");
(Node::Number(n as _), 2)
}
}
#[derive(Debug, PartialEq)]
enum Reduction {
None,
Partial,
Full,
}
impl Node {
fn explode(&mut self) -> bool {
self.explode_inner(0, &mut None, &mut None) != Reduction::None
}
fn explode_inner<'a, 'b>(
&'a mut self,
depth: usize,
previous_number: &'b mut Option<&'a mut usize>,
for_next: &'b mut Option<usize>,
) -> Reduction {
match (self, &for_next) {
(Node::Number(n), Some(x)) => {
*n += x;
*for_next = None;
Reduction::Full
}
(Node::Number(n), None) => {
*previous_number = Some(n);
Reduction::None
}
(s @ Node::Pair(_), _) if depth == 4 => {
let (left, right) = s.number_pair_or_panic();
if let Some(prev) = previous_number {
**prev += left;
}
*for_next = Some(*right);
*s = Node::Number(0);
Reduction::Partial
}
(Node::Pair(p), _) => {
let left = p.0.explode_inner(depth + 1, previous_number, for_next);
if left != Reduction::Full {
p.1.explode_inner(depth + 1, previous_number, for_next)
} else {
left
}
}
}
}
fn number_pair_or_panic(&self) -> (&usize, &usize) {
match &self {
Node::Pair(p) => (p.0.number_or_panic(), p.1.number_or_panic()),
_ => unreachable!(),
}
}
fn number_or_panic(&self) -> &usize {
match &self {
Node::Number(n) => n,
_ => unreachable!(),
}
}
}
fn part1(parsed: &Parsed) -> usize {
unimplemented!()
}
fn part2(parsed: &Parsed) -> usize {
unimplemented!()
}
fn main() {
let input = parse_input(&read_file(DAY));
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
}
#[cfg(test)]
mod tests {
use super::*;
use aoc2021::*;
use test_case::test_case;
const TEST_INPUT_SINGLE_ADDITION: &str = "[[[[4,3],4],4],[7,[[8,4],9]]]
[1,1]";
const TEST_INPUT: &str = "[1,2]
[[1,2],3]
[9,[8,7]]
[[1,9],[8,5]]
[[[[1,2],[3,4]],[[5,6],[7,8]]],9]
[[[9,[3,8]],[[0,9],6]],[[[3,7],[4,9]],3]]
[[[[1,3],[5,3]],[[1,3],[8,7]]],[[[4,9],[6,9]],[[8,2],[7,3]]]]";
#[test]
fn test_example_parsing() {
let [first, second]: [Node; 2] = parse_input(TEST_INPUT_SINGLE_ADDITION).try_into().unwrap();
assert_eq!(
first,
Node::Pair(box (
Node::Pair(box (Node::Pair(box (Node::Pair(box (Node::Number(4), Node::Number(3))), Node::Number(4))), Node::Number(4))),
Node::Pair(box (Node::Number(7), Node::Pair(box (Node::Pair(box (Node::Number(8), Node::Number(4),)), Node::Number(9),))))
))
);
assert_eq!(second, Node::Pair(box (Node::Number(1), Node::Number(1))));
}
#[test]
fn test_node_display() {
for (actual, expected) in parse_input(TEST_INPUT).into_iter().zip(TEST_INPUT.lines()) {
assert_eq!(expected, actual.to_string());
}
}
#[test_case("[[[[[9,8],1],2],3],4]" => "[[[[0,9],2],3],4]")]
#[test_case("[7,[6,[5,[4,[3,2]]]]]" => "[7,[6,[5,[7,0]]]]")]
#[test_case("[[6,[5,[4,[3,2]]]],1]" => "[[6,[5,[7,0]]],3]")]
#[test_case("[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]" => "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]")]
#[test_case("[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]" => "[[3,[2,[8,0]]],[9,[5,[7,0]]]]")]
fn test_single_explosion(raw: &str) -> String {
let mut i = parse_node(raw).0;
assert!(i.explode());
i.to_string()
}
/*
test!(part1() == 0);
test!(part2() == 0);
bench!(part1() == 0);
bench!(part2() == 0);
bench_input!(Vec::len => 0);
*/
}