Day 6 complete!

This commit is contained in:
2019-12-16 20:51:35 -08:00
parent 83a3acbc05
commit 46f4275376
2 changed files with 126 additions and 19 deletions

View File

@@ -8,6 +8,7 @@ mod wiremap;
use crate::args::Command;
use crate::endchannel::channel;
use crate::fuel::calculate_fuel;
use crate::orbits::Object;
use crate::wiremap::WireMap;
use std::cmp::{max,min};
@@ -105,8 +106,26 @@ fn main() {
}
Command::Orbits(uom) => {
println!("Got orbits.");
println!("Got orbits:");
uom.show();
println!("Base map has {} orbits.", uom.num_orbits());
match uom.find_path(&Object::new("YOU"), &Object::new("SAN")) {
None =>
println!("There is no path from you to Santa. :("),
Some(path) => {
print!("The path from you to Santa is: ");
let mut path_iter = path.iter().peekable();
while let Some(x) = path_iter.next() {
print!("{}", x);
if path_iter.peek().is_some() {
print!(" => ");
}
}
println!("");
println!(" ... so the number of transfers needed is {}", path.len() - 3);
}
}
}
}
}

View File

@@ -8,6 +8,16 @@ pub enum Object {
Object(String),
}
impl Object {
pub fn new(s: &str) -> Object {
if s == "COM" {
Object::CenterOfMass
} else {
Object::Object(s.to_string())
}
}
}
impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -21,11 +31,7 @@ impl FromStr for Object {
type Err = ();
fn from_str(s: &str) -> Result<Object,Self::Err> {
if s == "COM" {
Ok(Object::CenterOfMass)
} else {
Ok(Object::Object(s.to_string()))
}
Ok(Object::new(s))
}
}
@@ -45,8 +51,12 @@ impl FromStr for UniversalOrbitMap {
continue;
}
let mut splits = nextline.split(')');
let obj1str = splits.next().unwrap_or_else(|| panic!("Bad orbit line: {}", nextline));
let obj2str = splits.next().unwrap_or_else(|| panic!("Bad orbit line: {}", nextline));
let obj1str = splits.next()
.unwrap_or_else(|| panic!("Bad orbit line: {}", nextline))
.trim();
let obj2str = splits.next()
.unwrap_or_else(|| panic!("Bad orbit line: {}", nextline))
.trim();
let obj1 = Object::from_str(&obj1str)?;
let obj2 = Object::from_str(&obj2str)?;
if let Some(prev) = orbits.get_mut(&obj1) {
@@ -113,26 +123,104 @@ impl UniversalOrbitMap {
}
pub fn num_orbits(&self) -> usize {
let mut result = 0;
let mut search_stack = vec![(Object::CenterOfMass, 0)];
let mut total = 0;
for obj1 in self.objects().iter() {
for obj2 in self.objects().iter() {
if (obj1 != obj2) && self.indirectly_orbits(obj1, obj2) {
result += 1;
while let Some((nextobj, len)) = search_stack.pop() {
total += len;
match self.orbits.get(&nextobj) {
None => { }
Some(objs) => {
for obj in objs {
search_stack.push((obj.clone(), len + 1));
}
}
}
}
result
total
}
pub fn show(&self) {
for (key, values) in self.orbits.iter() {
print!("{} => ", key);
for value in values.iter() {
print!("{} ", value);
}
println!("");
}
}
fn path_from_origin(&self, obj: &Object) -> Option<Vec<Object>> {
let mut search_stack = vec![(Object::CenterOfMass, vec![Object::CenterOfMass])];
let mut total = 0;
while let Some((nextobj, mut path)) = search_stack.pop() {
if &nextobj == obj {
path.push(nextobj);
return Some(path);
}
match self.orbits.get(&nextobj) {
None => { }
Some(objs) => {
path.push(nextobj);
for obj in objs {
search_stack.push((obj.clone(), path.clone()));
}
}
}
}
panic!("Can't reach object from origin: {}", obj);
}
pub fn find_path(&self, obj1: &Object, obj2: &Object) -> Option<Vec<Object>> {
let obj1path = self.path_from_origin(obj1)?;
let obj2path = self.path_from_origin(obj2)?;
println!("path1: {:?}", obj1path);
println!("path2: {:?}", obj2path);
let joinpoint = find_join_point(&obj1path, &obj2path)?;
let path1stub = obj1path.iter().skip_while(|x| x != &&joinpoint);
let path2stub = obj2path.iter().skip_while(|x| x != &&joinpoint);
let mut result = vec![];
for x in path1stub { result.push(x.clone()); }
result.reverse();
for x in path2stub.skip(1) { result.push(x.clone()); }
println!("result: {:?}", result);
Some(result)
}
}
fn find_join_point<T: Clone + PartialEq>(list1: &Vec<T>, list2: &Vec<T>) -> Option<T> {
for possible in list1.iter().rev() {
if list2.contains(possible) {
return Some(possible.clone());
}
}
None
}
#[test]
fn examples() {
let input = "COM)B\nB)C\nC)D\nD)E\nE)F\nB)G\nG)H\nD)I\nE)J\nJ)K\nK)L";
let map = UniversalOrbitMap::from_str(&input).unwrap();
assert!(map.orbits(&Object::Object("B".to_string()), &Object::CenterOfMass));
assert!(map.indirectly_orbits(&Object::Object("B".to_string()), &Object::CenterOfMass));
assert!(map.indirectly_orbits(&Object::Object("E".to_string()),&Object::CenterOfMass));
let input1 = "COM)B\nB)C\nC)D\nD)E\nE)F\nB)G\nG)H\nD)I\nE)J\nJ)K\nK)L";
let map = UniversalOrbitMap::from_str(&input1).unwrap();
assert!(map.orbits(&Object::new("B"), &Object::CenterOfMass));
assert!(map.indirectly_orbits(&Object::new("B"), &Object::CenterOfMass));
assert!(map.indirectly_orbits(&Object::new("E"),&Object::CenterOfMass));
assert_eq!(map.num_orbits(), 42);
let day6_contents = std::fs::read("inputs/day6").unwrap();
let day6_str = std::str::from_utf8(&day6_contents).unwrap();
let day6map = UniversalOrbitMap::from_str(&day6_str).unwrap();
assert_eq!(day6map.num_orbits(), 204521);
let input2 = "COM)B\nB)C\nC)D\nD)E\nE)F\nB)G\nG)H\nD)I\nE)J\nJ)K\nK)L\nK)YOU\nI)SAN";
let map2 = UniversalOrbitMap::from_str(input2).unwrap();
assert_eq!(map2.find_path(&Object::new("YOU"), &Object::new("SAN")).unwrap().len(), 7);
}