some functions for 2021 day 12
[?]
Dec 15, 2021, 2:56 AM
NULMDMUUK5JASG23MB2EIYNUF665YLOBSRDNE2TCXY5OAO4SFNUQCDependencies
Change contents
- file addition: day12.rs[4.16]
#![feature(hash_drain_filter)]use std::collections::HashMap;use std::iter::once;use std::ops::Deref;fn main() {use std::io::BufRead;let filename = std::env::args().nth(1).expect("Expected filename");let mut graph = build_graph(&mut parse_edges(&mut std::io::BufReader::new(std::fs::File::open(filename.deref()).unwrap(),).lines().flat_map(Result::ok),));trim_graph(&mut graph);}fn parse_edges<I: Iterator<Item = S>, S: Deref<Target = str>>(source: &mut I,) -> impl Iterator<Item = (String, String)> + '_ {source.filter_map(|l| {let mut s = l.split('-').map(str::trim).map(std::borrow::ToOwned::to_owned);let lhs = s.next()?;let rhs = s.next()?;match s.next() {None => Some(()),Some(_) => None,}?;Some((lhs, rhs))})}fn trim_graph(graph: &mut HashMap<usize, HashMap<usize, u128>>) -> bool {use std::collections::HashSet;let mut ever_changed = false;loop {let mut changed = false;let reachable: HashSet<_> = graph.values().flat_map(|e| e.keys()).copied().chain(once(0)).collect();let reached: HashSet<_> = graph.keys().copied().collect();graph.drain_filter(|s, e| {e.drain_filter(|t, n| {if *n == 0 || !reached.contains(t) {changed = true;true} else {false}}).for_each(drop);if *s > 1 && (!reachable.contains(s) || e.is_empty()) {changed = true;true} else {false}}).for_each(drop);if changed {ever_changed = true;} else {break;}}ever_changed}fn build_graph<I: Iterator<Item = (S, T)>,S: Deref<Target = str>,T: Deref<Target = str>,>(source: &mut I,) -> HashMap<usize, HashMap<usize, u128>> {let mut large = HashMap::new();let mut small = HashMap::new();number(&mut small, String::from("start"));number(&mut small, String::from("end"));let mut result = HashMap::new();for (s, t) in source.flat_map(|(s, t)| {let s = s.deref();let t = t.deref();let (l, s, t) = if upper(s) {(true, s, t)} else if upper(t) {(true, t, s)} else {(false, s, t)};if l {let v = large.entry(s.to_owned()).or_insert_with(Vec::new);let t = number(&mut small, t.to_owned());let d = v.clone();v.push(t);Box::new(d.into_iter().map(move |s| (s, t)))as Box<dyn Iterator<Item = (usize, usize)>>} else {let s = number(&mut small, s.to_owned());let t = number(&mut small, t.to_owned());Box::new(once((s, t)))as Box<dyn Iterator<Item = (usize, usize)>>}}).flat_map(|(s, t)| [(s, t), (t, s)]).filter(|(s, t)| *s != 1 && *t != 0){result.entry(s).or_insert_with(HashMap::new).entry(t).and_modify(|v| *v += 1).or_insert(1);}result}fn upper(x: &str) -> bool {x.chars().next().map(char::is_uppercase).unwrap_or(false)}fn number<K: Eq + std::hash::Hash>(repo: &mut HashMap<K, usize>,name: K,) -> usize {let s = repo.len();*repo.entry(name).or_insert(s)} - edit in 2021/Cargo.toml at line 37[2.5329]
[[bin]]name = "day12"path = "day12.rs"