use std::borrow::BorrowMut; use petgraph::dot::*; use petgraph::prelude::*; use petgraph::*; fn do_weights(g: &mut Graph<(String, u64), ()>, root_dir: NodeIndex) { for edge in g.clone().edges_directed(root_dir, Outgoing) { let mut target_weight = g.node_weight(edge.target()).unwrap(); if target_weight.1 == 0 { do_weights(g, edge.target()); target_weight = g.node_weight(edge.target()).unwrap(); } g.node_weight_mut(root_dir).unwrap().1 += target_weight.1; } } fn main() { const INPUT: &str = include_str!("../input.txt"); let mut g = DiGraph::<(String, u64), (), u32>::new(); let invalid_index: NodeIndex = NodeIndex::from(u32::MAX); let mut curr_dir: NodeIndex = invalid_index; let mut root_dir: NodeIndex = invalid_index; for line in INPUT.lines() { if line.starts_with("$ cd") { let new_dir = &line[5..]; if new_dir == ".." { curr_dir = g .edges_directed(curr_dir, Incoming) .next() .unwrap() .source(); } else { let prev_dir = curr_dir; curr_dir = g.add_node((new_dir.to_string() + "/", 0)); if prev_dir == invalid_index { root_dir = curr_dir; } else { g.add_edge(prev_dir, curr_dir, ()); } } } else if line.starts_with("$ ls") { continue; } else { let (size, name) = line.split_once(' ').unwrap(); if size == "dir" { continue; } let size: u64 = size.parse().unwrap(); let n = g.add_node((name.to_string(), size)); g.add_edge(curr_dir, n, ()); } } do_weights(g.borrow_mut(), root_dir); println!("{:?}\n\n", Dot::with_config(&g, &[Config::EdgeNoLabel])); let total = g .node_weights() .filter(|(n, w)| n.ends_with("/") && *w <= 100000) .map(|(_, w)| w) .sum::(); println!("total: {total}"); let used_space = g.node_weight(root_dir).unwrap().1; let free_space = 70000000 - used_space; let need_to_free = 30000000 - free_space; let delete = g .node_weights() .filter(|(n, w)| n.ends_with("/") && *w > need_to_free) .map(|(_, w)| w) .min() .unwrap(); println!("delete size: {delete}"); }