diff --git a/Cargo.toml b/Cargo.toml index 19c9ed6..4c581cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ edition = "2018" reqwest = "0.9.22" tempfile = "3.1.0" futures = "0.3.1" +petgraph = "0.5.1" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f0906f5..a623ad1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(str_strip)] extern crate reqwest; extern crate tempfile; @@ -8,6 +9,7 @@ use crate::problem4::lib::Problem4; use crate::problem5::lib::Problem5; use crate::problem6::lib::Problem6; use crate::problem7::lib::Problem7; +use crate::problem8::lib::Problem8; mod problem1; mod problem2; @@ -16,6 +18,7 @@ mod problem4; mod problem5; mod problem6; mod problem7; +mod problem8; mod util; @@ -53,7 +56,11 @@ fn main() { // problem6.run_part1(); // problem6.run_part2(); - let problem7 = Problem7::new(&util::get_problem(7)); + /*let problem7 = Problem7::new(&util::get_problem(7)); problem7.run_part1(); - problem7.run_part2(); + problem7.run_part2();*/ + + let problem8 = Problem8::new(&util::get_problem(8)); + problem8.run_part1(); + problem8.run_part2(); } diff --git a/src/problem7/lib.rs b/src/problem7/lib.rs index 985848b..b7d280c 100644 --- a/src/problem7/lib.rs +++ b/src/problem7/lib.rs @@ -1,46 +1,169 @@ +use std::collections::{HashMap, HashSet}; +use petgraph::algo::{all_simple_paths, has_path_connecting}; +use petgraph::Graph; +use petgraph::graph::{DiGraph, Node, NodeIndex, node_index}; +use petgraph::dot::{Dot, Config}; use crate::Problem; -use std::collections::HashSet; +use std::fs::File; +use std::io::Write; +use petgraph::visit::{Dfs, depth_first_search, DfsEvent}; pub struct Problem7 { - groups: Vec>, + // + rules: DiGraph, + node_lookup: HashMap, } +impl Problem7 { -impl Problem7 {} + fn index_to_name(&self, node_ind: NodeIndex) -> Option { + let v = self.node_lookup.iter().filter_map(|(k, v)| { + if *v == node_index(node_ind.index()){ + Some(k.clone()) + } else { + None + } + }).collect::>(); + match v.first() { + None => {None} + Some(v) => {Some(v.clone())} + } + } + + fn dfs(&self, multiplier: u64, node: NodeIndex) -> u64 { + println!("starting dfs at {:?}, {:?}", multiplier, node); + + let mut sum : u64 = 0; + let mut multiplier : u64 = multiplier; + let mut last_multiple : Vec = vec![1]; + + let result = depth_first_search(&self.rules, Some(node), |event| { + match event { + DfsEvent::Discover(q, e) => { + println!("Discover Node : Node : {:?}", self.index_to_name(q)); + Ok(()) + } + DfsEvent::BackEdge(q, e) => { + println!("Back Edge : NodeA : {:?} ---> NodeB : {:?}", self.index_to_name(q), self.index_to_name(e)); + Err(event) + } + DfsEvent::TreeEdge(q, e) => { + println!("Tree : NodeA : {:?} ---> NodeB : {:?}", self.index_to_name(q), self.index_to_name(e)); + let edge_weight = *(self.rules.edges_connecting(q, e).filter_map(|a| { + Some(*a.weight()) + }).collect::>().first().unwrap()); + + multiplier *= edge_weight as u64; + println!("Tree Meta : Multiplier : {:?} ==== Edge Weight : {:?}", multiplier, edge_weight); + last_multiple.push(edge_weight as u64); + + Ok(()) + } + DfsEvent::CrossForwardEdge(q, e) => { + println!("Cross : Start {:?} ---> End {:?} ==== Sum@Now {}", self.index_to_name(q), self.index_to_name(e), sum); + + let edge_weight = *(self.rules.edges_connecting(q, e).filter_map(|a| { + Some(*a.weight()) + }).collect::>().first().unwrap()); + + multiplier *= edge_weight as u64; + println!("Cross Meta : Multiplier : {:?} ==== Edge Weight : {:?}", multiplier, edge_weight); + last_multiple.push(edge_weight as u64); + + sum += self.dfs(multiplier, e); + println!("Sum after : {}", sum); + Ok(()) + } + DfsEvent::Finish(q, e) => { // finds leaf and reverses back up + println!("Finish : Node {:?}", self.index_to_name(q)); + sum += multiplier as u64; + multiplier /= last_multiple.pop().unwrap(); + if last_multiple.len() == 0 { + sum -= 1; + println!("reached root"); + } + println!("Finish - calcs : sum {:?}, multiplier {:?}", sum, multiplier); + Ok(()) + } + } + }); + println!("exiting dfs"); + sum + } +} impl Problem for Problem7 { fn new(input: &String) -> Self { - Problem7 { - groups: input - .split("\n\n") - .filter_map(|s| { - let s = s.trim().split("\n"); - let mut sets = Vec::new(); - for i in s { - let v : HashSet = i.chars().filter_map(|c| { - if c.is_whitespace() { - None - } else { - Some(c) - } - }).collect::>(); - sets.push(v); + let mut r = Problem7 { + rules: DiGraph::new(), + node_lookup: Default::default(), + }; + r.node_lookup.insert("shiny gold bag".to_string(), r.rules.add_node("shiny gold bag".to_string())); + for line in input.split("\n") { + let s = line.trim(); + if !s.is_empty() { + let mut split = s.split("contain"); + let mut node = split.next().unwrap().trim(); + if node.ends_with("s") { + node = &node[0..node.len() - 1] + } + + r.node_lookup.insert(node.to_string(), r.rules.add_node(node.to_string())); + } + } + + for line in input.split("\n") { + let s = line.trim(); + if !s.is_empty() { + let mut split = s.split("contain"); + let mut node = split.next().unwrap().trim(); + if node.ends_with("s") { + node = &node[0..node.len() - 1] + } + let root = r.node_lookup.get(node).unwrap(); + + let raw_subs = split.next().unwrap().split(", "); + for i in raw_subs { + let item = i.trim(); + if item.starts_with(char::is_numeric) { + let mut node = (&item[2..]).split(".").next().unwrap(); + if node.ends_with("s") { + node = &node[0..node.len() - 1] + } + let count = &item[..1].parse::().unwrap(); + r.rules.add_edge(*root, *r.node_lookup.get(node).unwrap(), *count); } - let mut iter = sets.iter(); - let intersection : HashSet = - iter.next().map(|set| iter.fold(set.clone(), |set1, set2| set1.intersection(set2).map(|c| *c).collect())).unwrap().clone(); - Some(intersection) - }).collect(), + } + } } + r } fn run_part1(&self) { + // println!("{:?}", self.node_lookup); + // let mut count = 0; + // for (k, v) in &self.node_lookup { + // let r = has_path_connecting(&self.rules, + // *self.node_lookup.get(k).unwrap(), + // *self.node_lookup.get("shiny gold bag").unwrap(), None); + // println!("{} : {}", k, r); + // if r { + // count += 1 + // } + // } + // println!("{}", count); + // let mut f = File::create("example.dot").unwrap(); + // let output = format!("{}", Dot::with_config(&self.rules, &[Config::EdgeNoLabel])); + // f.write_all(&output.as_bytes()).expect("could not write file"); } fn run_part2(&self) { + + println!("ending count = {:?}", self.dfs(1, node_index(self.node_lookup.get("shiny gold bag").unwrap().index()))); + } } diff --git a/src/problem8/lib.rs b/src/problem8/lib.rs new file mode 100644 index 0000000..45fed38 --- /dev/null +++ b/src/problem8/lib.rs @@ -0,0 +1,34 @@ + +use crate::Problem; + +pub struct Problem8 { + number_list: Vec, +} + +impl Problem8 {} + +impl Problem for Problem8 { + fn new(input: &String) -> Self { + Problem8 { + number_list: input + .split("\n") + .filter_map(|s| { + let s = s.trim(); + if !s.is_empty() { + Some(s.parse::().unwrap()) + } else { + None + } + }).collect(), + } + } + + fn run_part1(&self) { + + } + + fn run_part2(&self) { + + } +} + diff --git a/src/problem8/mod.rs b/src/problem8/mod.rs new file mode 100644 index 0000000..965f28e --- /dev/null +++ b/src/problem8/mod.rs @@ -0,0 +1 @@ +pub mod lib;