advent-of-code 2025.5.0

Solutions to Advent of Code
Documentation
use crate::input::{Input, on_error};

pub fn solve(input: &Input) -> Result<u64, String> {
    const HASH_BASE: u32 = 18;
    const HASH_MAX_VAL: usize =
        (HASH_BASE.pow(4) + HASH_BASE.pow(3) + HASH_BASE.pow(2) + HASH_BASE + 1) as usize;

    let part2 = input.is_part_two();

    let mut secret_num_sum = 0;
    let mut sequence_buys = [0_u16; HASH_MAX_VAL];

    for line in input.text.lines() {
        let mut this_sequence_buys = [false; HASH_MAX_VAL];
        let mut changes = 0_u32;
        let mut last_banana_value = 0;

        let mut n: u64 = line.parse().map_err(|_| on_error())?;
        for i in 0..2000 {
            n = (n ^ (n << 6)) & 16777215;
            n ^= n >> 5;
            n = (n ^ (n << 11)) & 16777215;

            let this_banana_value = (n % 10) as i8;
            let banan_value_change = this_banana_value - last_banana_value;
            last_banana_value = this_banana_value;

            changes =
                ((changes << 5) | ((banan_value_change + 9) as u32)) & 0b11111_11111_11111_11111;

            if i >= 3 && part2 {
                let hash_val = (HASH_BASE.pow(3) * ((changes >> 15) & 0b11111)
                    + HASH_BASE.pow(2) * ((changes >> 10) & 0b11111)
                    + HASH_BASE * ((changes >> 5) & 0b11111)
                    + (changes & 0b11111)) as usize;
                if !this_sequence_buys[hash_val] {
                    sequence_buys[hash_val] += this_banana_value as u16;
                    this_sequence_buys[hash_val] = true;
                }
            }
        }
        secret_num_sum += n;
    }

    Ok(if input.is_part_one() {
        secret_num_sum
    } else {
        *sequence_buys.iter().max().unwrap_or(&0) as u64
    })
}

#[test]
pub fn tests() {
    let test_input: &str = "1
10
100
2024";
    test_part_one_no_allocations!(test_input => 37_327_623);
    let test_input: &str = "1
2
3
2024";
    test_part_two_no_allocations!(test_input => 23);

    let real_input = include_str!("day22_input.txt");
    test_part_one_no_allocations!(real_input => 14_623_556_510);
    test_part_two_no_allocations!(real_input => 1701);
}