|
| 1 | +// Copyright (c) 2025 Lexi Robinson |
| 2 | +// |
| 3 | +// Licensed under the EUPL, Version 1.2 |
| 4 | +// |
| 5 | +// You may not use this work except in compliance with the Licence. |
| 6 | +// You should have received a copy of the Licence along with this work. If not, see: |
| 7 | +// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>. |
| 8 | +// See the Licence for the specific language governing permissions and limitations under the Licence. |
| 9 | + |
| 10 | +use std::collections::HashMap; |
| 11 | + |
| 12 | +use cached::{UnboundCache, cached_key}; |
| 13 | +use itertools::Itertools; |
| 14 | + |
| 15 | +use crate::AoCError; |
| 16 | + |
| 17 | +type Key = u32; |
| 18 | +type Store = HashMap<Key, Vec<Key>>; |
| 19 | + |
| 20 | +const fn to_id(input: &str) -> Key { |
| 21 | + // all ids are 3 ascii letters, so 7 bits each. |
| 22 | + let input = input.as_bytes(); |
| 23 | + let [a, b, c] = *input else { |
| 24 | + panic!("Code must be 3 bytes") |
| 25 | + }; |
| 26 | + ((a as u32) << 16) + ((b as u32) << 8) + (c as u32) |
| 27 | +} |
| 28 | + |
| 29 | +const START: Key = to_id("you"); |
| 30 | +const END: Key = to_id("out"); |
| 31 | + |
| 32 | +fn parse_line(input: String) -> crate::AoCResult<(Key, Vec<Key>)> { |
| 33 | + let (gate, outputs) = input |
| 34 | + .split_once(": ") |
| 35 | + .ok_or_else(|| AoCError::new("Line {input} doesn't have a :"))?; |
| 36 | + |
| 37 | + Ok((to_id(gate), outputs.split_whitespace().map(to_id).collect())) |
| 38 | +} |
| 39 | + |
| 40 | +cached_key! { |
| 41 | + FIND_PATHS: UnboundCache<Key, usize> = UnboundCache::with_capacity(600); |
| 42 | + Key = { id }; |
| 43 | + fn find_paths(id: Key, store: &Store) -> usize = { |
| 44 | + let my_outputs = &store[&id]; |
| 45 | + log::debug!("Hello I'm {id} and my friends are {my_outputs:?}"); |
| 46 | + my_outputs |
| 47 | + .iter() |
| 48 | + .copied() |
| 49 | + .map(|out_id| if out_id == END { 1 } else { find_paths(out_id, store)}) |
| 50 | + .sum::<usize>() |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> { |
| 55 | + let store: Store = data.map(parse_line).try_collect()?; |
| 56 | + let ret = find_paths(START, &store); |
| 57 | + Ok(ret.to_string()) |
| 58 | +} |
| 59 | + |
| 60 | +inventory::submit!(crate::AoCDay { |
| 61 | + year: "2025", |
| 62 | + day: "11", |
| 63 | + part_1: crate::AoCPart { |
| 64 | + main: part_1, |
| 65 | + example: part_1 |
| 66 | + }, |
| 67 | + part_2: None |
| 68 | +}); |
0 commit comments