Day 12 but bad
This commit is contained in:
parent
b93563d249
commit
148f240696
21
input/day12
Normal file
21
input/day12
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
KF-sr
|
||||||
|
OO-vy
|
||||||
|
start-FP
|
||||||
|
FP-end
|
||||||
|
vy-mi
|
||||||
|
vy-KF
|
||||||
|
vy-na
|
||||||
|
start-sr
|
||||||
|
FP-lh
|
||||||
|
sr-FP
|
||||||
|
na-FP
|
||||||
|
end-KF
|
||||||
|
na-mi
|
||||||
|
lh-KF
|
||||||
|
end-lh
|
||||||
|
na-start
|
||||||
|
wp-KF
|
||||||
|
mi-KF
|
||||||
|
vy-sr
|
||||||
|
vy-lh
|
||||||
|
sr-mi
|
|
@ -81,6 +81,7 @@ fn do_flash(mut hm: &mut FlashMap, mut flashing: &mut Vec<(i32, i32)>, mut flash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn print_flashes(map: &FlashMap, x_max: i32, y_max: i32) {
|
fn print_flashes(map: &FlashMap, x_max: i32, y_max: i32) {
|
||||||
let mut v: Vec<Vec<i32>> = Vec::new();
|
let mut v: Vec<Vec<i32>> = Vec::new();
|
||||||
for y in 0..y_max {
|
for y in 0..y_max {
|
||||||
|
|
275
src/day12.rs
Normal file
275
src/day12.rs
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::Day;
|
||||||
|
|
||||||
|
pub struct Day12(HashMap<String, Cave>);
|
||||||
|
|
||||||
|
impl Day for Day12 {
|
||||||
|
fn init(content: String) -> anyhow::Result<Self> {
|
||||||
|
let mut caves = HashMap::new();
|
||||||
|
|
||||||
|
for line in content.lines() {
|
||||||
|
let z = line.split('-').collect::<Vec<_>>();
|
||||||
|
let first = z[0];
|
||||||
|
let second = z[1];
|
||||||
|
|
||||||
|
{
|
||||||
|
let first_cave = caves.entry(first.to_string()).or_insert(Cave::new(first.into()));
|
||||||
|
first_cave.add_connection(second);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let second_cave = caves.entry(second.to_string()).or_insert(Cave::new(second.into()));
|
||||||
|
second_cave.add_connection(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(caves))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(&self) -> anyhow::Result<String> {
|
||||||
|
fn get_all_paths(caves: &HashMap<String, Cave>, complete_paths: &mut Vec<Vec<String>>, current_path: &Vec<String>, current_cave_idx: &str) {
|
||||||
|
if current_cave_idx == "end" {
|
||||||
|
complete_paths.push(current_path.clone());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_cave = caves.get(current_cave_idx).expect("This cave does not exist!").clone();
|
||||||
|
|
||||||
|
for connected_cave in current_cave.connections {
|
||||||
|
let current = caves.get(&connected_cave).unwrap();
|
||||||
|
match current.cave_type {
|
||||||
|
CaveType::Small => {
|
||||||
|
if current_path.iter().find(|&cave_pair| cave_pair == &connected_cave) != None {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_path = current_path.clone();
|
||||||
|
new_path.push(connected_cave.clone());
|
||||||
|
get_all_paths(&caves, complete_paths, &new_path, &connected_cave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut complete_paths = Vec::new();
|
||||||
|
let current_path = vec!["start".into()];
|
||||||
|
|
||||||
|
get_all_paths(&self.0, &mut complete_paths, ¤t_path, "start".into());
|
||||||
|
|
||||||
|
Ok(format!("{}", complete_paths.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(&self) -> anyhow::Result<String> {
|
||||||
|
let mut small_caves_thing: HashMap<Vec<String>, Vec<String>> = HashMap::<Vec<String>, Vec<String>>::new();
|
||||||
|
fn get_all_paths(caves: &HashMap<String, Cave>, complete_paths: &mut Vec<Vec<String>>, current_path: &Vec<String>, current_cave_idx: &str, small_caves_thing: &mut HashMap<Vec<String>, Vec<String>>) {
|
||||||
|
if current_cave_idx == "end" {
|
||||||
|
complete_paths.push(current_path.clone());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let current_cave = caves.get(current_cave_idx).expect("This cave does not exist!").clone();
|
||||||
|
|
||||||
|
let small_caves = {
|
||||||
|
let e = small_caves_thing.entry(current_path.clone()).or_insert(small_caves_visited_at_least_twice(caves, current_path));
|
||||||
|
e.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
for connected_cave in current_cave.connections {
|
||||||
|
if connected_cave == "start" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !small_caves.is_empty() {
|
||||||
|
let current = caves.get(&connected_cave).unwrap();
|
||||||
|
match current.cave_type {
|
||||||
|
CaveType::Small => {
|
||||||
|
if !(small_caves.len() == 1 && small_caves[0] != connected_cave) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_path = current_path.clone();
|
||||||
|
new_path.push(connected_cave.clone());
|
||||||
|
get_all_paths(&caves, complete_paths, &new_path, &connected_cave, small_caves_thing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut complete_paths = Vec::new();
|
||||||
|
let current_path = vec!["start".into()];
|
||||||
|
|
||||||
|
get_all_paths(&self.0, &mut complete_paths, ¤t_path, "start", &mut small_caves_thing);
|
||||||
|
|
||||||
|
Ok(format!("{}", complete_paths.len()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn small_caves_visited_at_least_twice(caves: &HashMap<String, Cave>, current_path: &Vec<String>) -> Vec<String> {
|
||||||
|
let mut small_cave_indices = HashMap::new();
|
||||||
|
for cave_name in current_path {
|
||||||
|
let c = caves.get(cave_name).expect("how?");
|
||||||
|
if c.cave_type == CaveType::Small {
|
||||||
|
let e = small_cave_indices.entry(cave_name).or_insert(0);
|
||||||
|
*e += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return small_cave_indices.iter().filter(|(_, &b)| b > 1).map(|(&a, _)| a.clone()).collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
|
||||||
|
enum CaveType {
|
||||||
|
Large,
|
||||||
|
Small,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
|
||||||
|
struct Cave {
|
||||||
|
connections: Vec<String>,
|
||||||
|
cave_type: CaveType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cave {
|
||||||
|
fn add_connection<T>(&mut self, name: T) where T: ToString {
|
||||||
|
self.connections.push(name.to_string());
|
||||||
|
self.connections.sort();
|
||||||
|
self.connections.dedup();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(cave_name: String) -> Self {
|
||||||
|
let cave_type = if cave_name.chars().nth(0).unwrap().is_uppercase() {
|
||||||
|
CaveType::Large
|
||||||
|
} else {
|
||||||
|
CaveType::Small
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
cave_type,
|
||||||
|
connections: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day12 {
|
||||||
|
fn search(&self, cur: &str, had: &HashMap<String, i32>, part1: bool) -> i32 {
|
||||||
|
let mut had = had.clone();
|
||||||
|
if had.values().any(|&i| i > 0) || part1 {
|
||||||
|
if had.contains_key(cur) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cur == "start" && had.contains_key("start") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if cur == "end" {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if cur.chars().all(|x| x.is_lowercase()) {
|
||||||
|
let e = had.entry(cur.into()).or_insert(0);
|
||||||
|
*e += 1;
|
||||||
|
}
|
||||||
|
let n = self.0.get(cur).unwrap();
|
||||||
|
return n.connections.iter().map(|c| self.search(c, &mut had, part1)).sum::<i32>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{Day, Day12};
|
||||||
|
|
||||||
|
const INPUT_1: &str = r"start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end";
|
||||||
|
|
||||||
|
const INPUT_2: &str = r"dc-end
|
||||||
|
HN-start
|
||||||
|
start-kj
|
||||||
|
dc-start
|
||||||
|
dc-HN
|
||||||
|
LN-dc
|
||||||
|
HN-end
|
||||||
|
kj-sa
|
||||||
|
kj-HN
|
||||||
|
kj-dc";
|
||||||
|
|
||||||
|
const INPUT_3: &str = r"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]
|
||||||
|
fn part1_test_1() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(INPUT_1.to_string())?;
|
||||||
|
assert_eq!("10", d.part1()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_test_2() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(INPUT_2.to_string())?;
|
||||||
|
assert_eq!("19", d.part1()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_test_3() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(INPUT_3.to_string())?;
|
||||||
|
assert_eq!("226", d.part1()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn part1_real() -> anyhow::Result<()> {
|
||||||
|
// let d = Day12::init(crate::load_input("12")?)?;
|
||||||
|
// assert_eq!("4885", d.part1()?);
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_test_1() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(INPUT_1.to_string())?;
|
||||||
|
assert_eq!("36", d.part2()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_test_2() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(INPUT_2.to_string())?;
|
||||||
|
assert_eq!("103", d.part2()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are very slow, so they are commented out.
|
||||||
|
// #[test]
|
||||||
|
// fn part2_test_3() -> anyhow::Result<()> {
|
||||||
|
// let d = Day12::init(INPUT_3.to_string())?;
|
||||||
|
// assert_eq!("3509", d.part2()?);
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_real() -> anyhow::Result<()> {
|
||||||
|
let d = Day12::init(crate::load_input("12")?)?;
|
||||||
|
assert_eq!("117095", d.part2()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use crate::day08::Day08;
|
||||||
use crate::day09::Day09;
|
use crate::day09::Day09;
|
||||||
use crate::day10::Day10;
|
use crate::day10::Day10;
|
||||||
use crate::day11::Day11;
|
use crate::day11::Day11;
|
||||||
|
use crate::day12::Day12;
|
||||||
|
|
||||||
mod day;
|
mod day;
|
||||||
mod day01;
|
mod day01;
|
||||||
|
@ -27,6 +28,7 @@ mod day08;
|
||||||
mod day09;
|
mod day09;
|
||||||
mod day10;
|
mod day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
|
mod day12;
|
||||||
|
|
||||||
fn load_input(day: &str) -> Result<String> {
|
fn load_input(day: &str) -> Result<String> {
|
||||||
read_to_string(format!("./input/day{}", day)).map_err(|x| x.into())
|
read_to_string(format!("./input/day{}", day)).map_err(|x| x.into())
|
||||||
|
@ -72,7 +74,8 @@ fn main() -> anyhow::Result<()> {
|
||||||
Box::new(Day08::init(load_input("08")?)?),
|
Box::new(Day08::init(load_input("08")?)?),
|
||||||
Box::new(Day09::init(load_input("09")?)?),
|
Box::new(Day09::init(load_input("09")?)?),
|
||||||
Box::new(Day10::init(load_input("10")?)?),
|
Box::new(Day10::init(load_input("10")?)?),
|
||||||
Box::new(Day11::init(load_input("11")?)?),];
|
Box::new(Day11::init(load_input("11")?)?),
|
||||||
|
Box::new(Day12::init(load_input("12")?)?),];
|
||||||
|
|
||||||
let _verbosity = matches.occurrences_of("v");
|
let _verbosity = matches.occurrences_of("v");
|
||||||
if matches.is_present("all") {
|
if matches.is_present("all") {
|
||||||
|
|
Loading…
Reference in a new issue