advent_of_code/year2018/
day08.rs

1use crate::input::Input;
2type InputNumber = u8;
3
4pub fn solve(input: &Input) -> Result<usize, String> {
5    let data = input
6        .text
7        .split_whitespace()
8        .map(|word| {
9            word.parse::<InputNumber>()
10                .map_err(|error| format!("Invalid input: {error}"))
11        })
12        .collect::<Result<Vec<InputNumber>, _>>()?;
13    Ok(evaluate_node(&data, 0, input.is_part_one())?.1)
14}
15
16fn evaluate_node(
17    data: &[InputNumber],
18    start: usize,
19    part1: bool,
20) -> Result<(usize, usize), String> {
21    if data.len() < start + 2 {
22        return Err("Invalid input".to_string());
23    }
24
25    let mut children_values = Vec::new();
26    let mut offset_after_children = start + 2;
27
28    let num_child_nodes = data[start];
29    for _ in 0..num_child_nodes {
30        let (offset_after_child, child_value) = evaluate_node(data, offset_after_children, part1)?;
31        offset_after_children = offset_after_child;
32        children_values.push(child_value);
33    }
34
35    let metadata_entries = data[start + 1] as usize;
36    let node_value = data
37        .iter()
38        .skip(offset_after_children)
39        .take(metadata_entries)
40        .map(|&metadata| {
41            if part1 || num_child_nodes == 0 {
42                metadata as usize
43            } else if metadata >= 1 && metadata as usize <= children_values.len() {
44                children_values[(metadata - 1) as usize]
45            } else {
46                0
47            }
48        })
49        .sum::<usize>()
50        + if part1 {
51            children_values.iter().sum()
52        } else {
53            0
54        };
55
56    let offset_after_current = offset_after_children
57        .checked_add(metadata_entries)
58        .ok_or("Overflow in computation")?;
59    Ok((offset_after_current, node_value))
60}
61
62#[test]
63fn tests() {
64    use crate::input::{test_part_one, test_part_two};
65
66    test_part_one!("2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2" => 138);
67    test_part_two!("2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2" => 66);
68
69    let input = include_str!("day08_input.txt");
70    test_part_one!(input => 47112);
71    test_part_two!(input => 28237);
72}