day25: problem 1 solution - cheated with dot

This commit is contained in:
2023-12-24 22:33:20 -08:00
parent 881d0b08ad
commit 342f4c1883
3 changed files with 449 additions and 0 deletions

171
25/src/main.rs Normal file
View File

@ -0,0 +1,171 @@
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
use itertools::Itertools;
use petgraph::algo::connected_components;
use petgraph::dot::Dot;
use petgraph::prelude::*;
use petgraph::visit::{depth_first_search, DfsEvent, IntoEdgeReferences, IntoNodeIdentifiers, IntoNodeReferences};
use rayon::prelude::*;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader, Lines};
use std::time::Instant;
// BOILERPLATE
type InputIter = Lines<BufReader<File>>;
fn get_input() -> InputIter {
let f = File::open("input").unwrap();
let br = BufReader::new(f);
br.lines()
}
fn main() {
let start = Instant::now();
let ans1 = problem1(get_input());
let duration = start.elapsed();
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
let start = Instant::now();
let ans2 = problem2(get_input());
let duration = start.elapsed();
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
}
// PARSE
struct Circuit {
graph: UnGraph<String, String>,
nodes: HashMap<String, Node>,
}
#[derive(Debug, Clone)]
struct Node {
targets: Vec<String>,
index: Option<NodeIndex>,
}
impl Node {
fn with_index(mut self, index: NodeIndex) -> Self {
self.index = Some(index);
self
}
}
impl<T: BufRead> From<Lines<T>> for Circuit {
fn from(lines: Lines<T>) -> Self {
let mut graph = UnGraph::default();
let mut nodes = HashMap::new();
for line in lines.map(|v| v.unwrap()) {
let (source, targets_s) = line.split_once(": ").unwrap();
let targets = targets_s.split_whitespace().map(|s| s.to_string()).collect_vec();
nodes.insert(
source.to_string(),
Node {
targets,
index: Some(graph.add_node(source.to_string())),
},
);
}
for (name, node) in nodes.iter_mut() {
for target in &node.targets {
let target_idx = match graph.node_references().find(|n| n.1 == target).map(|n| n.0) {
Some(target) => target,
None => graph.add_node(target.to_string()),
};
graph.add_edge(node.index.unwrap(), target_idx, format!("{}-{}", name, target));
}
}
Self { graph, nodes }
}
}
impl Circuit {
// returns the set of nodes on each side
fn find_critical_edges(&self, removals: usize) -> (Vec<String>, Vec<String>) {
let bar = ProgressBar::new(self.graph.edge_references().combinations(removals).try_len().unwrap() as u64)
.with_style(
ProgressStyle::with_template(
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
)
.unwrap(),
);
// for set in self.graph.edge_references().combinations(removals).progress_with(bar) {
let set = [("zcp", "zjm"), ("rsg", "nsk"), ("jks", "rfg")]
.iter()
.flat_map(|(src, dst)| {
self.graph.edge_references().filter(|e| self.graph[e.source()] == *src && self.graph[e.target()] == *dst || self.graph[e.target()] == *src && self.graph[e.source()] == *dst)
}).collect_vec();
let mut local_graph: StableUnGraph<_, _> = self.graph.clone().into();
for wire in &set {
local_graph.remove_edge(wire.id());
}
let local_graph = UnGraph::from(local_graph);
if connected_components(&local_graph) == 2 {
// each edge will have one leg in each component, so return the set of connected nodes
let mut left = Vec::new();
depth_first_search(&local_graph, Some(set[0].source()), |event| {
if let DfsEvent::Discover(n, t) = event {
left.push(local_graph[n].to_string());
}
});
let mut right = Vec::new();
depth_first_search(&local_graph, Some(set[0].target()), |event| {
if let DfsEvent::Discover(n, t) = event {
right.push(local_graph[n].to_string());
}
});
return (left, right);
}
// }
panic!("no cutline found");
}
}
// PROBLEM 1 solution
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
let circuit = Circuit::from(input);
println!("{:?}", Dot::new(&circuit.graph));
let (left, right) = circuit.find_critical_edges(3);
(left.len() * right.len()) as u64
}
// PROBLEM 2 solution
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
0
}
#[cfg(test)]
mod tests {
use crate::*;
use std::io::Cursor;
const EXAMPLE: &str = &"jqt: rhn xhk nvd
rsh: frs pzl lsr
xhk: hfx
cmg: qnr nvd lhk bvb
rhn: xhk bvb hfx
bvb: xhk hfx
pzl: lsr hfx nvd
qnr: nvd
ntq: jqt hfx bvb xhk
nvd: lhk
lsr: lhk
rzs: qnr cmg lsr rsh
frs: qnr lhk lsr";
#[test]
fn problem1_example() {
let c = Cursor::new(EXAMPLE);
assert_eq!(problem1(c.lines()), 54);
}
#[test]
fn problem2_example() {
let c = Cursor::new(EXAMPLE);
assert_eq!(problem2(c.lines()), 0);
}
}