Skip to main content

advent_of_code/year2020/
day15.rs

1use crate::input::Input;
2
3pub fn solve(input: &Input) -> Result<u32, String> {
4    const NEVER_SEEN: u32 = 0;
5
6    let target_turn: u32 = input.part_values(2020, 30_000_000);
7    let mut value_to_turn: Vec<u32> = vec![0; target_turn as usize];
8    let mut next_number = 0;
9    let mut turn = 0;
10
11    for (idx, parsed_starting_number) in input
12        .text
13        .split(',')
14        .map(|s| {
15            s.parse::<u32>()
16                .map_err(|error| format!("Invalid input: {error}"))
17        })
18        .enumerate()
19    {
20        let starting_number = parsed_starting_number?;
21        if starting_number > target_turn {
22            return Err(format!("Too high starting number: {starting_number}"));
23        }
24        next_number = starting_number;
25        value_to_turn[next_number as usize] = (idx + 1) as u32;
26        turn += 1;
27    }
28
29    while turn != target_turn {
30        if next_number >= target_turn {
31            return Err(format!("Too big number: {next_number}"));
32        }
33
34        let last_spoken_turn = std::mem::replace(&mut value_to_turn[next_number as usize], turn);
35
36        next_number = if last_spoken_turn == NEVER_SEEN {
37            // If that was the first time the number has been spoken, the current player says 0:
38            0
39        } else {
40            // If the number had been spoken before; the current player announces
41            // how many turns apart the number is from when it was previously spoken:
42            turn - last_spoken_turn
43        };
44
45        turn += 1;
46    }
47
48    Ok(next_number)
49}
50
51#[test]
52pub fn tests() {
53    let example = "0,3,6";
54    test_part_one!(example => 436);
55    test_part_two!(example => 175_594);
56
57    let real_input = include_str!("day15_input.txt");
58    test_part_one!(real_input => 1194);
59    test_part_two!(real_input => 48710);
60}