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::args::Command;
|
||||||
use crate::endchannel::channel;
|
use crate::endchannel::channel;
|
||||||
use crate::fuel::calculate_fuel;
|
use crate::fuel::calculate_fuel;
|
||||||
|
use crate::orbits::Object;
|
||||||
use crate::wiremap::WireMap;
|
use crate::wiremap::WireMap;
|
||||||
use std::cmp::{max,min};
|
use std::cmp::{max,min};
|
||||||
|
|
||||||
@@ -105,8 +106,26 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Command::Orbits(uom) => {
|
Command::Orbits(uom) => {
|
||||||
println!("Got orbits.");
|
println!("Got orbits:");
|
||||||
|
uom.show();
|
||||||
println!("Base map has {} orbits.", uom.num_orbits());
|
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),
|
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 {
|
impl fmt::Display for Object {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -21,11 +31,7 @@ impl FromStr for Object {
|
|||||||
type Err = ();
|
type Err = ();
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Object,Self::Err> {
|
fn from_str(s: &str) -> Result<Object,Self::Err> {
|
||||||
if s == "COM" {
|
Ok(Object::new(s))
|
||||||
Ok(Object::CenterOfMass)
|
|
||||||
} else {
|
|
||||||
Ok(Object::Object(s.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,8 +51,12 @@ impl FromStr for UniversalOrbitMap {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut splits = nextline.split(')');
|
let mut splits = nextline.split(')');
|
||||||
let obj1str = splits.next().unwrap_or_else(|| panic!("Bad orbit line: {}", nextline));
|
let obj1str = splits.next()
|
||||||
let obj2str = splits.next().unwrap_or_else(|| panic!("Bad orbit line: {}", nextline));
|
.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 obj1 = Object::from_str(&obj1str)?;
|
||||||
let obj2 = Object::from_str(&obj2str)?;
|
let obj2 = Object::from_str(&obj2str)?;
|
||||||
if let Some(prev) = orbits.get_mut(&obj1) {
|
if let Some(prev) = orbits.get_mut(&obj1) {
|
||||||
@@ -113,26 +123,104 @@ impl UniversalOrbitMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_orbits(&self) -> usize {
|
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() {
|
while let Some((nextobj, len)) = search_stack.pop() {
|
||||||
for obj2 in self.objects().iter() {
|
total += len;
|
||||||
if (obj1 != obj2) && self.indirectly_orbits(obj1, obj2) {
|
|
||||||
result += 1;
|
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]
|
#[test]
|
||||||
fn examples() {
|
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 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(&input).unwrap();
|
let map = UniversalOrbitMap::from_str(&input1).unwrap();
|
||||||
assert!(map.orbits(&Object::Object("B".to_string()), &Object::CenterOfMass));
|
assert!(map.orbits(&Object::new("B"), &Object::CenterOfMass));
|
||||||
assert!(map.indirectly_orbits(&Object::Object("B".to_string()), &Object::CenterOfMass));
|
assert!(map.indirectly_orbits(&Object::new("B"), &Object::CenterOfMass));
|
||||||
assert!(map.indirectly_orbits(&Object::Object("E".to_string()),&Object::CenterOfMass));
|
assert!(map.indirectly_orbits(&Object::new("E"),&Object::CenterOfMass));
|
||||||
assert_eq!(map.num_orbits(), 42);
|
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