day25: problem 1 solution - cheated with dot
This commit is contained in:
171
25/src/main.rs
Normal file
171
25/src/main.rs
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user