diff --git a/.aoc_tiles/tiles/2024/24.png b/.aoc_tiles/tiles/2024/24.png index 89f755a..b966019 100644 Binary files a/.aoc_tiles/tiles/2024/24.png and b/.aoc_tiles/tiles/2024/24.png differ diff --git a/.aoc_tiles/tiles/2024/25.png b/.aoc_tiles/tiles/2024/25.png index e1ab8d3..a1daeb8 100644 Binary files a/.aoc_tiles/tiles/2024/25.png and b/.aoc_tiles/tiles/2024/25.png differ diff --git a/README.md b/README.md index bd4c125..dfc7c92 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- 2024 - 46 ⭐ - Rust + 2024 - 48 ⭐ - Rust

@@ -74,4 +74,7 @@ + + + diff --git a/src/day25.rs b/src/day25.rs new file mode 100644 index 0000000..2b8d7b4 --- /dev/null +++ b/src/day25.rs @@ -0,0 +1,143 @@ +use aoc_runner_derive::aoc; +use itertools::Itertools; + +enum LockKey { + Lock, + Key, +} + +#[derive(Clone, Debug)] +struct LockPile { + keys: Vec>, + locks: Vec>, +} + +fn parse_grid(lines: &Vec<&str>) -> (LockKey, Vec) { + assert_eq!(lines.len(), 7); + if lines[0].chars().all(|c| c == '#') { + // lock + let mut pins = vec![0; 5]; + for row in 1..lines.len() { + let row_s = lines[row]; + for i in 0..row_s.len() { + if row_s.chars().nth(i) == Some('#') { + pins[i] = row + } + } + } + (LockKey::Lock, pins) + } else if lines[6].chars().all(|c| c == '#') { + // key + let mut pins = vec![5; 5]; + for row in (1..lines.len()).rev() { + let row_s = lines[row]; + for i in 0..row_s.len() { + if row_s.chars().nth(i) == Some('#') { + pins[i] = 6 - row + } + } + } + (LockKey::Key, pins) + } else { + panic!("not a lock or a key: {:?}", lines); + } +} + +fn parse(input: &str) -> LockPile { + let mut locks = Vec::new(); + let mut keys = Vec::new(); + let mut accum: Vec<&str> = Vec::new(); + for line in input.lines() { + if line == "" { + let (lk, pins) = parse_grid(&accum); + match lk { + LockKey::Lock => locks.push(pins), + LockKey::Key => keys.push(pins), + } + accum.clear(); + } else { + accum.push(line); + } + } + if accum.len() != 0 { + let (lk, pins) = parse_grid(&accum); + match lk { + LockKey::Lock => locks.push(pins), + LockKey::Key => keys.push(pins), + } + } + LockPile { keys, locks } +} + +fn test_lock_key(lock: &Vec, key: &Vec) -> bool { + !lock.iter().zip(key.iter()).any(|(lp, kp)| lp + kp > 5) +} + +#[aoc(day25, part1)] +pub fn part1(input: &str) -> i64 { + let lockpile = parse(input); + + lockpile + .locks + .iter() + .cartesian_product(lockpile.keys.iter()) + .filter(|(l, k)| test_lock_key(l, k)) + .count() as i64 +} + +#[aoc(day25, part2)] +pub fn part2(_input: &str) -> String { + "run the other solutions for day 25 part 2!".to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + const EXAMPLE: &str = "##### +.#### +.#### +.#### +.#.#. +.#... +..... + +##### +##.## +.#.## +...## +...#. +...#. +..... + +..... +#.... +#.... +#...# +#.#.# +#.### +##### + +..... +..... +#.#.. +###.. +###.# +###.# +##### + +..... +..... +..... +#.... +#.#.. +#.#.# +#####"; + + #[test] + fn part1_example() { + assert_eq!(part1(EXAMPLE), 3); + } + + #[test] + fn part2_example() {} +} diff --git a/src/lib.rs b/src/lib.rs index 6cfecaf..ee2182e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ pub mod day21; pub mod day22; pub mod day23; pub mod day24; +pub mod day25; pub mod day3; pub mod day4; pub mod day5;