advent_of_code/year2017/
day06.rs1use 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}