From 06c8b775fa536f6a2142cb39c47594208b9ad0aa Mon Sep 17 00:00:00 2001 From: kageru Date: Sun, 12 Dec 2021 12:41:23 +0100 Subject: [PATCH] Add day 12 part 1 --- 2021/inputs/day12 | 24 ++++++++ 2021/src/bin/day12.rs | 124 ++++++++++++++++++++++++++++++++++++++++++ 2021/src/teststuff.rs | 9 +++ 3 files changed, 157 insertions(+) create mode 100644 2021/inputs/day12 create mode 100644 2021/src/bin/day12.rs diff --git a/2021/inputs/day12 b/2021/inputs/day12 new file mode 100644 index 0000000..fbb547b --- /dev/null +++ b/2021/inputs/day12 @@ -0,0 +1,24 @@ +yb-start +de-vd +rj-yb +rj-VP +OC-de +MU-de +end-DN +vd-end +WK-vd +rj-de +DN-vd +start-VP +DN-yb +vd-MU +DN-rj +de-VP +yb-OC +start-rj +oa-MU +yb-de +oa-VP +jv-MU +yb-MU +end-OC diff --git a/2021/src/bin/day12.rs b/2021/src/bin/day12.rs new file mode 100644 index 0000000..84c58a5 --- /dev/null +++ b/2021/src/bin/day12.rs @@ -0,0 +1,124 @@ +#![feature(test)] +extern crate test; +use std::collections::{HashMap, HashSet}; + +use aoc2021::common::*; +use itertools::Itertools; + +const DAY: usize = 12; +type Parsed<'a> = HashMap, Vec>>; + +const EMPTY: Vec> = Vec::new(); + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +enum Node<'a> { + Start, + End, + Small(&'a str), + Big(&'a str), +} + +impl<'a> From<&'a str> for Node<'a> { + fn from(s: &'a str) -> Self { + match s { + "start" => Node::Start, + "end" => Node::End, + cave if cave.chars().all(|c| c.is_ascii_uppercase()) => Node::Big(cave), + cave if cave.chars().all(|c| c.is_ascii_lowercase()) => Node::Small(cave), + _ => unreachable!(), + } + } +} + +fn parse_input(raw: &str) -> Parsed { + raw.lines() + .map(|l| l.split_once('-').unwrap()) + .map(|(from, to)| (Node::from(from), Node::from(to))) + .flat_map(|(a, b)| [(a, b), (b, a)]) // connections always go both ways + .into_group_map() +} + +fn part1(parsed: &Parsed) -> usize { + possible_paths(parsed, &Node::Start, HashSet::new()) +} + +fn possible_paths<'a>(map: &'a Parsed, position: &'a Node<'a>, mut visited: HashSet<&'a Node<'a>>) -> usize { + if position == &Node::End { + return 1; + } + if matches!(position, &Node::Small(_)) { + visited.insert(position); + } + map.get(position) + .unwrap() + .iter() + .filter(|&p| p != &Node::Start) + .filter(|p| !visited.contains(p)) + .map(|p| possible_paths(map, p, visited.clone())) + .sum() +} + +fn part2(parsed: &Parsed) -> usize { + unimplemented!() +} + +fn main() { + let raw = read_file(DAY); + let input = parse_input(&raw); + println!("Part 1: {}", part1(&input)); + println!("Part 2: {}", part2(&input)); +} + +#[cfg(test)] +mod tests { + use super::*; + use aoc2021::*; + + const TEST_INPUT: &str = "start-A +start-b +A-c +A-b +b-d +A-end +b-end"; + + const TEST_INPUT_2: &str = "dc-end +HN-start +start-kj +dc-start +dc-HN +LN-dc +HN-end +kj-sa +kj-HN +kj-dc"; + + const TEST_INPUT_3: &str = "fs-end +he-DX +fs-he +start-DX +pj-DX +end-zg +zg-sl +zg-pj +pj-he +RW-he +fs-DX +pj-RW +zg-RW +start-pj +he-WI +zg-he +pj-fs +start-RW"; + + test!(part1() == 10); + test!(with _2: part1() == 19); + test!(with _3: part1() == 226); + test!(part2() == 36); + test!(with _2: part2() == 103); + test!(with _3: part2() == 3509); + bench!(part1() == 4411); + bench!(part2() == 0); + bench_input!(HashMap::len => 13); +} diff --git a/2021/src/teststuff.rs b/2021/src/teststuff.rs index f4f0814..6e572c9 100644 --- a/2021/src/teststuff.rs +++ b/2021/src/teststuff.rs @@ -34,4 +34,13 @@ macro_rules! test { } } }; + (with $input: ident: $part: ident $(<$gen: literal>)? ($($param: expr),*) == $expected:expr) => { + paste::paste! { + #[test] + fn [<$part $($gen)? _$input:lower _test>]() { + let input = parse_input([]); + assert_eq!($part $(::<$gen>)? (&input$(, $param)*), $expected); + } + } + }; }