Skip to main content

advent_of_code/year2017/
day06.rs

1use crate::input::Input;
2use std::collections::HashMap;
3use std::collections::hash_map::Entry;
4
5pub fn solve(input: &Input) -> Result<u32, String> {
6    const MAX_ITERATIONS: u32 = 1_000_000;
7
8    let mut memory_banks: Vec<u32> = input
9        .text
10        .split_ascii_whitespace()
11        .enumerate()
12        .map(|(index, word)| {
13            word.parse::<u32>()
14                .map_err(|error| format!("Invalid input at word {}: {}", index + 1, error))
15        })
16        .collect::<Result<_, _>>()?;
17
18    if memory_banks.is_empty() {
19        return Err("Invalid empty input".to_string());
20    }
21
22    let mut seen_before = HashMap::new();
23
24    for current_step in 0..MAX_ITERATIONS {
25        match seen_before.entry(memory_banks.clone()) {
26            Entry::Occupied(value) => {
27                return Ok(current_step - input.part_values(0_u32, *value.get()));
28            }
29            Entry::Vacant(entry) => {
30                entry.insert(current_step);
31            }
32        }
33
34        let bank_to_redistribute =
35            memory_banks
36                .iter()
37                .enumerate()
38                .fold(0, |acc, (index, &blocks)| {
39                    if blocks > memory_banks[acc] {
40                        index
41                    } else {
42                        acc
43                    }
44                });
45
46        let mut blocks_to_distribute = memory_banks[bank_to_redistribute];
47        memory_banks[bank_to_redistribute] = 0;
48        let mut current_index = bank_to_redistribute;
49        while blocks_to_distribute > 0 {
50            current_index = (current_index + 1) % memory_banks.len();
51            memory_banks[current_index] += 1;
52            blocks_to_distribute -= 1;
53        }
54    }
55
56    Err(format!("Aborting after {MAX_ITERATIONS} iterations"))
57}
58
59#[test]
60fn tests() {
61    let real_input = include_str!("day06_input.txt");
62    test_part_one!(real_input => 12841);
63    test_part_two!(real_input => 8038);
64    test_part_one_error!(
65        "12 12 hi" =>
66        "Invalid input at word 3: invalid digit found in string".to_string()
67    );
68}