Complete terribly inefficient day 12
Too lazy to refactor
This commit is contained in:
parent
29d71ea159
commit
ac7f7ee114
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -99,3 +99,11 @@ dependencies = [
|
||||
"anyhow",
|
||||
"common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day12"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"common",
|
||||
]
|
||||
|
10
crates/day12/Cargo.toml
Normal file
10
crates/day12/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "day12"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
common = { path = "../common" }
|
24
crates/day12/src/input/input.txt
Normal file
24
crates/day12/src/input/input.txt
Normal file
@ -0,0 +1,24 @@
|
||||
pf-pk
|
||||
ZQ-iz
|
||||
iz-NY
|
||||
ZQ-end
|
||||
pf-gx
|
||||
pk-ZQ
|
||||
ZQ-dc
|
||||
NY-start
|
||||
NY-pf
|
||||
NY-gx
|
||||
ag-ZQ
|
||||
pf-start
|
||||
start-gx
|
||||
BN-ag
|
||||
iz-pf
|
||||
ag-FD
|
||||
pk-NY
|
||||
gx-pk
|
||||
end-BN
|
||||
ag-pf
|
||||
iz-pk
|
||||
pk-ag
|
||||
iz-end
|
||||
iz-BN
|
7
crates/day12/src/input/test1.txt
Normal file
7
crates/day12/src/input/test1.txt
Normal file
@ -0,0 +1,7 @@
|
||||
start-A
|
||||
start-b
|
||||
A-c
|
||||
A-b
|
||||
b-d
|
||||
A-end
|
||||
b-end
|
10
crates/day12/src/input/test2.txt
Normal file
10
crates/day12/src/input/test2.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
crates/day12/src/input/test3.txt
Normal file
18
crates/day12/src/input/test3.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
|
167
crates/day12/src/main.rs
Normal file
167
crates/day12/src/main.rs
Normal file
@ -0,0 +1,167 @@
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use common::instrument;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
const INPUT: &str = include_str!("input/input.txt");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
enum Cave {
|
||||
Start,
|
||||
End,
|
||||
Small(String),
|
||||
Big(String),
|
||||
}
|
||||
|
||||
impl FromStr for Cave {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
if s == "start" {
|
||||
Ok(Cave::Start)
|
||||
} else if s == "end" {
|
||||
Ok(Cave::End)
|
||||
} else {
|
||||
match s.chars().all(|c| c.is_uppercase()) {
|
||||
true => Ok(Cave::Big(s.to_string())),
|
||||
false => Ok(Cave::Small(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Cave {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Cave::Start => write!(f, "start"),
|
||||
Cave::End => write!(f, "end"),
|
||||
Cave::Small(s) | Cave::Big(s) => write!(f, "{}", s),
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct CaveSystem {
|
||||
connections: HashMap<Cave, Vec<Cave>>,
|
||||
}
|
||||
|
||||
impl FromStr for CaveSystem {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
let mut connections = HashMap::new();
|
||||
|
||||
for line in s.trim().lines() {
|
||||
let mut parts = line.split('-');
|
||||
let origin = parts.next().ok_or(anyhow!("missing origin"))?;
|
||||
let origin = origin.parse::<Cave>()?;
|
||||
let destination = parts.next().ok_or(anyhow!("missing destination"))?;
|
||||
let destination = destination.parse::<Cave>()?;
|
||||
let entry = connections.entry(origin.clone()).or_insert_with(Vec::new);
|
||||
entry.push(destination.clone());
|
||||
let entry = connections.entry(destination).or_insert_with(Vec::new);
|
||||
entry.push(origin);
|
||||
}
|
||||
|
||||
Ok(CaveSystem { connections })
|
||||
}
|
||||
}
|
||||
|
||||
impl CaveSystem {
|
||||
fn get_paths(&self, path: &Vec<Cave>, one_small_twice: bool) -> Result<Vec<Vec<Cave>>> {
|
||||
let mut paths = vec![];
|
||||
let origin = path.last().ok_or(anyhow!("empty path"))?;
|
||||
|
||||
if let Some(destinations) = self.connections.get(&origin) {
|
||||
for destination in destinations {
|
||||
paths.append(&mut match destination {
|
||||
Cave::Start => continue,
|
||||
Cave::End => {
|
||||
let mut path = path.clone();
|
||||
path.push(destination.clone());
|
||||
Ok(vec![path])
|
||||
}
|
||||
Cave::Big(_) => {
|
||||
let mut path = path.clone();
|
||||
path.push(destination.clone());
|
||||
self.get_paths(&path, one_small_twice)
|
||||
}
|
||||
Cave::Small(_) => {
|
||||
if !path.contains(destination) {
|
||||
let mut path = path.clone();
|
||||
path.push(destination.clone());
|
||||
self.get_paths(&path, one_small_twice)
|
||||
} else if one_small_twice {
|
||||
let mut small_counts = HashMap::new();
|
||||
for small in path.iter().filter(|c| {
|
||||
if let Cave::Small(_) = c {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
let entry = small_counts.entry(small.clone()).or_insert(0);
|
||||
*entry += 1;
|
||||
}
|
||||
if small_counts.values().any(|&count| count > 1) {
|
||||
continue;
|
||||
} else {
|
||||
let mut path = path.clone();
|
||||
path.push(destination.clone());
|
||||
self.get_paths(&path, one_small_twice)
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}?);
|
||||
}
|
||||
}
|
||||
Ok(paths)
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_part1(input: &str) -> Result<usize> {
|
||||
let cave_system = input.parse::<CaveSystem>()?;
|
||||
|
||||
let paths = cave_system.get_paths(&vec![Cave::Start], false)?;
|
||||
|
||||
Ok(paths.len())
|
||||
}
|
||||
|
||||
fn solve_part2(input: &str) -> Result<usize> {
|
||||
let cave_system = input.parse::<CaveSystem>()?;
|
||||
|
||||
let paths = cave_system.get_paths(&vec![Cave::Start], true)?;
|
||||
|
||||
Ok(paths.len())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
instrument!(solve_part1(INPUT).unwrap(), solve_part2(INPUT).unwrap());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const TEST_INPUT1: &str = include_str!("input/test1.txt");
|
||||
const TEST_INPUT2: &str = include_str!("input/test2.txt");
|
||||
const TEST_INPUT3: &str = include_str!("input/test3.txt");
|
||||
|
||||
#[test]
|
||||
fn solves_part1() {
|
||||
assert_eq!(solve_part1(TEST_INPUT1).unwrap(), 10);
|
||||
assert_eq!(solve_part1(TEST_INPUT2).unwrap(), 19);
|
||||
assert_eq!(solve_part1(TEST_INPUT3).unwrap(), 226);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solves_part2() {
|
||||
assert_eq!(solve_part2(TEST_INPUT1).unwrap(), 36);
|
||||
assert_eq!(solve_part2(TEST_INPUT2).unwrap(), 103);
|
||||
assert_eq!(solve_part2(TEST_INPUT3).unwrap(), 3509);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user