2021: day12: part 1
This commit is contained in:
parent
d0f3b941ce
commit
c439b3a265
22
aoc2021/input/day12.txt
Normal file
22
aoc2021/input/day12.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
GC-zi
|
||||||
|
end-zv
|
||||||
|
lk-ca
|
||||||
|
lk-zi
|
||||||
|
GC-ky
|
||||||
|
zi-ca
|
||||||
|
end-FU
|
||||||
|
iv-FU
|
||||||
|
lk-iv
|
||||||
|
lk-FU
|
||||||
|
GC-end
|
||||||
|
ca-zv
|
||||||
|
lk-GC
|
||||||
|
GC-zv
|
||||||
|
start-iv
|
||||||
|
zv-QQ
|
||||||
|
ca-GC
|
||||||
|
ca-FU
|
||||||
|
iv-ca
|
||||||
|
start-lk
|
||||||
|
zv-FU
|
||||||
|
start-zi
|
7
aoc2021/input/day12_provided1.txt
Normal file
7
aoc2021/input/day12_provided1.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
10
aoc2021/input/day12_provided2.txt
Normal file
10
aoc2021/input/day12_provided2.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
dc-end
|
||||||
|
HN-start
|
||||||
|
start-kj
|
||||||
|
dc-start
|
||||||
|
dc-HN
|
||||||
|
LN-dc
|
||||||
|
HN-end
|
||||||
|
kj-sa
|
||||||
|
kj-HN
|
||||||
|
kj-dc
|
18
aoc2021/input/day12_provided3.txt
Normal file
18
aoc2021/input/day12_provided3.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
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
|
140
aoc2021/src/day12.rs
Normal file
140
aoc2021/src/day12.rs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day12.txt");
|
||||||
|
|
||||||
|
pub fn run() -> Result<String> {
|
||||||
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Result<usize> {
|
||||||
|
let cave_map: CaveMap = input.try_into()?;
|
||||||
|
|
||||||
|
cave_map.count_paths()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Cave<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
small: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Cave<'a> {
|
||||||
|
fn is_end(&self) -> bool {
|
||||||
|
self.name == "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_start(&self) -> bool {
|
||||||
|
self.name == "start"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_small(&self) -> bool {
|
||||||
|
self.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Cave<'a> {
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
Cave {
|
||||||
|
name: s,
|
||||||
|
small: s.chars().all(char::is_lowercase),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::hash::Hash for Cave<'a> {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::cmp::PartialEq for Cave<'a> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> std::cmp::Eq for Cave<'a> {}
|
||||||
|
|
||||||
|
struct CaveMap<'a> {
|
||||||
|
connections: HashMap<Cave<'a>, Vec<Cave<'a>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CaveMap<'a> {
|
||||||
|
fn count_paths(&self) -> Result<usize> {
|
||||||
|
let start = *self
|
||||||
|
.connections
|
||||||
|
.keys()
|
||||||
|
.find(|cave| cave.is_start())
|
||||||
|
.context("couldn't find starting cave")?;
|
||||||
|
Ok(self.count_paths_rec(start, HashSet::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_paths_rec(&self, from: Cave<'a>, mut small_seen: HashSet<Cave<'a>>) -> usize {
|
||||||
|
if from.is_end() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if from.is_small() {
|
||||||
|
if small_seen.contains(&from) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
small_seen.insert(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut paths = 0;
|
||||||
|
for dst in &self.connections[&from] {
|
||||||
|
paths += self.count_paths_rec(*dst, small_seen.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
paths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a str> for CaveMap<'a> {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(s: &'a str) -> Result<Self> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for line in s.lines().map(str::trim) {
|
||||||
|
let (src, dst) = line
|
||||||
|
.split_once('-')
|
||||||
|
.context("couldn't parse cave connection")?;
|
||||||
|
map.entry(src.into())
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(dst.into());
|
||||||
|
map.entry(dst.into())
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(src.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CaveMap { connections: map })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const PROVIDED1: &str = include_str!("../input/day12_provided1.txt");
|
||||||
|
const PROVIDED2: &str = include_str!("../input/day12_provided2.txt");
|
||||||
|
const PROVIDED3: &str = include_str!("../input/day12_provided3.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
assert_eq!(part1(PROVIDED1).unwrap(), 10);
|
||||||
|
assert_eq!(part1(PROVIDED2).unwrap(), 19);
|
||||||
|
assert_eq!(part1(PROVIDED3).unwrap(), 226);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(INPUT).unwrap(), 5252);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,4 +11,5 @@ pub mod day08;
|
||||||
pub mod day09;
|
pub mod day09;
|
||||||
pub mod day10;
|
pub mod day10;
|
||||||
pub mod day11;
|
pub mod day11;
|
||||||
|
pub mod day12;
|
||||||
pub mod day13;
|
pub mod day13;
|
||||||
|
|
|
@ -13,6 +13,7 @@ use aoc2021::day08;
|
||||||
use aoc2021::day09;
|
use aoc2021::day09;
|
||||||
use aoc2021::day10;
|
use aoc2021::day10;
|
||||||
use aoc2021::day11;
|
use aoc2021::day11;
|
||||||
|
use aoc2021::day12;
|
||||||
use aoc2021::day13;
|
use aoc2021::day13;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
@ -28,6 +29,7 @@ fn main() -> Result<()> {
|
||||||
day09::run,
|
day09::run,
|
||||||
day10::run,
|
day10::run,
|
||||||
day11::run,
|
day11::run,
|
||||||
|
day12::run,
|
||||||
day13::run,
|
day13::run,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue