Day 12
This commit is contained in:
parent
1b1571c323
commit
1bf6e92261
|
@ -0,0 +1,25 @@
|
|||
we-NX
|
||||
ys-px
|
||||
ys-we
|
||||
px-end
|
||||
yq-NX
|
||||
px-NX
|
||||
yq-px
|
||||
qk-yq
|
||||
pr-NX
|
||||
wq-EY
|
||||
pr-oe
|
||||
wq-pr
|
||||
ys-end
|
||||
start-we
|
||||
ys-start
|
||||
oe-DW
|
||||
EY-oe
|
||||
end-oe
|
||||
pr-yq
|
||||
pr-we
|
||||
wq-start
|
||||
oe-NX
|
||||
yq-EY
|
||||
ys-wq
|
||||
ys-pr
|
|
@ -36,7 +36,7 @@ pub fn day11() {
|
|||
|
||||
println!("{:?}", grid);
|
||||
|
||||
for step in 0..100 {
|
||||
for _step in 0..100 {
|
||||
let (new, flashed) = grid.step();
|
||||
// println!("after step: {}, new grid: {:?}", step + 1, new);
|
||||
grid = new;
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Formatter;
|
||||
|
||||
pub fn day12() {
|
||||
// 10 paths, 36
|
||||
// let input = r#"
|
||||
// start-A
|
||||
// start-b
|
||||
// A-c
|
||||
// A-b
|
||||
// b-d
|
||||
// A-end
|
||||
// b-end"#;
|
||||
// 19 paths, 103
|
||||
// let input = r#"
|
||||
// dc-end
|
||||
// HN-start
|
||||
// start-kj
|
||||
// dc-start
|
||||
// dc-HN
|
||||
// LN-dc
|
||||
// HN-end
|
||||
// kj-sa
|
||||
// kj-HN
|
||||
// kj-dc
|
||||
// "#;
|
||||
// 226 paths, 3059
|
||||
// let input = 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
|
||||
// "#;
|
||||
let input = include_str!("../input/day12.txt");
|
||||
|
||||
let graph = parse_graph(&input);
|
||||
println!("{:?}", graph);
|
||||
|
||||
println!("{:?}", count_paths(&graph, false));
|
||||
println!("{:?}", count_paths(&graph, true));
|
||||
}
|
||||
|
||||
fn parse_graph(input: &'static str) -> Graph {
|
||||
let mut nodes = HashSet::new();
|
||||
let mut connections: HashMap<Node, Vec<Node>> = HashMap::new();
|
||||
for line in input.trim().lines() {
|
||||
let (a, b) = line.trim().split_once("-").unwrap();
|
||||
let first: Node = a.into();
|
||||
let second: Node = b.into();
|
||||
nodes.insert(first.clone());
|
||||
nodes.insert(second.clone());
|
||||
connections
|
||||
.entry(first.clone())
|
||||
.or_insert(vec![])
|
||||
.push(second.clone());
|
||||
connections.entry(second).or_insert(vec![]).push(first);
|
||||
}
|
||||
|
||||
Graph { nodes, connections }
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
enum Node {
|
||||
Start,
|
||||
End,
|
||||
Small(&'static str),
|
||||
Big(&'static str),
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn big(&self) -> bool {
|
||||
match self {
|
||||
Self::Big(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Node {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Start => write!(f, "start"),
|
||||
Self::End => write!(f, "end"),
|
||||
Self::Small(s) | Self::Big(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Node {
|
||||
fn from(s: &'static str) -> Self {
|
||||
if s == "start" {
|
||||
Self::Start
|
||||
} else if s == "end" {
|
||||
Self::End
|
||||
} else if s.chars().all(|c| c.is_uppercase()) {
|
||||
Self::Big(s)
|
||||
} else {
|
||||
Self::Small(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Graph {
|
||||
nodes: HashSet<Node>,
|
||||
connections: HashMap<Node, Vec<Node>>,
|
||||
}
|
||||
|
||||
fn count_paths(g: &Graph, allow_visiting_small_twice: bool) -> usize {
|
||||
let mut queue: VecDeque<(Vec<&Node>, bool)> = VecDeque::new();
|
||||
queue.push_front((vec![&Node::Start], false));
|
||||
let mut count = 0;
|
||||
|
||||
while let Some((path, mut seen_any_small_twice)) = queue.pop_front() {
|
||||
let last = path.last().unwrap().clone();
|
||||
|
||||
if last == &Node::End {
|
||||
// println!("{:?}", path);
|
||||
count += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// current is small and seen current before
|
||||
if !last.big() && path.iter().rev().skip(1).any(|&n| n == last) {
|
||||
// if visting small twice is always prohibited (part 1), or we're revisting the start,
|
||||
// or visiting a _single_ small twice is allowed but we've already done it
|
||||
if !allow_visiting_small_twice || last == &Node::Start || seen_any_small_twice {
|
||||
continue;
|
||||
}
|
||||
// note that we've now seen a single small cave twice, so any paths descended from this
|
||||
// one can't do so themselves
|
||||
seen_any_small_twice = true;
|
||||
}
|
||||
|
||||
for connected in &g.connections[last] {
|
||||
let mut new_path = path.clone();
|
||||
new_path.push(connected);
|
||||
queue.push_back((new_path, seen_any_small_twice));
|
||||
}
|
||||
}
|
||||
|
||||
count
|
||||
}
|
|
@ -10,7 +10,8 @@ mod day08;
|
|||
mod day09;
|
||||
mod day10;
|
||||
mod day11;
|
||||
mod day12;
|
||||
|
||||
fn main() {
|
||||
day11::day11();
|
||||
day12::day12();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue