Day 6 complete!
This commit is contained in:
21
src/main.rs
21
src/main.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
src/orbits.rs
124
src/orbits.rs
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user