Add day 12 part 1
This commit is contained in:
parent
8ccab04d6f
commit
06c8b775fa
|
@ -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
|
|
@ -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<Node<'a>, Vec<Node<'a>>>;
|
||||
|
||||
const EMPTY: Vec<Node<'_>> = 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);
|
||||
}
|
|
@ -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([<TEST_INPUT $input>]);
|
||||
assert_eq!($part $(::<$gen>)? (&input$(, $param)*), $expected);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user