Add day06

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2019-12-07 20:37:50 -05:00
parent 491bb87ee3
commit 2cd3fd8efa
2 changed files with 147 additions and 0 deletions

132
day06/Day06.rs Normal file
View File

@@ -0,0 +1,132 @@
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
io::{self, Read},
};
#[allow(unused_macros)]
macro_rules! todo {
($($tt:tt)*) => { unimplemented!($($tt)*) };
}
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn get_input_string() -> io::Result<String> {
let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer)?;
Ok(buffer)
}
fn main() -> Result<()> {
let orbit_list: Vec<Orbit> = get_input_string()?
.trim()
.lines()
.map(|line| {
let mut split = line.split(")");
Orbit {
parent: split.next().unwrap().to_string(),
child: split.next().unwrap().to_string(),
}
}).collect();
let mut orbit_graph = OrbitGraph::default();
for orbit in orbit_list.iter() {
orbit_graph.add_orbit(orbit.clone());
}
part1(&orbit_list, &orbit_graph);
part2(&orbit_list, &orbit_graph);
Ok(())
}
fn part1(orbit_list: &Vec<Orbit>, orbit_graph: &OrbitGraph) {
let bodies: HashSet<String> = orbit_list.iter()
.map(|o| o.child.clone())
.collect();
let total: usize = bodies.iter()
.map(|body| orbit_graph.indirect_count(body))
.sum();
println!("Part 1: {}", total);
}
fn part2(orbit_list: &Vec<Orbit>, orbit_graph: &OrbitGraph) {
let common = orbit_graph.common_parent("YOU", "SAN")
.expect("no common parent between YOU and SAN");
let common_dist = orbit_graph.indirect_count(common);
let hops1 = orbit_graph.indirect_count("YOU") - common_dist - 1;
let hops2 = orbit_graph.indirect_count("SAN") - common_dist - 1;
println!("Part 2: {}", hops1 + hops2);
}
#[derive(Debug, Clone)]
struct Orbit {
parent: String,
child: String,
}
#[derive(Debug, Default)]
struct OrbitGraph {
graph: HashMap<String, Vec<String>>,
orbits: HashMap<String, String>,
count_cache: RefCell<HashMap<String, usize>>,
}
impl OrbitGraph {
fn add_orbit(&mut self, Orbit { parent, child }: Orbit) {
let child_list = self.graph.entry(parent.clone()).or_insert(Vec::new());
child_list.push(child.clone());
assert!(self.orbits.insert(child, parent).is_none());
}
fn indirect_count(&self, body: &str) -> usize {
{
let cache = self.count_cache.borrow();
if let Some(count) = cache.get(body) {
return *count;
}
}
if let Some(parent) = self.orbits.get(body) {
let count = 1 + self.indirect_count(parent);
{
let mut cache = self.count_cache.borrow_mut();
cache.insert(body.to_string(), count);
}
count
} else {
0
}
}
fn common_parent(&self, first: &str, second: &str) -> Option<&str> {
let first_parent = self.orbits.get(first);
let second_parent = self.orbits.get(second);
// One of the parents is the root, which is the common parent for everyone
if first_parent.is_none() || second_parent.is_none() {
return None;
}
let first_parent = first_parent.unwrap();
let second_parent= second_parent.unwrap();
// Common parent found
if first_parent == second_parent {
return Some(first_parent);
}
let depth1 = self.indirect_count(first);
let depth2 = self.indirect_count(second);
if depth1 < depth2 {
self.common_parent(first, second_parent)
} else if depth2 < depth1 {
self.common_parent(first_parent, second)
} else {
self.common_parent(first_parent, second_parent)
}
}
}