170 lines
5.6 KiB
Rust
170 lines
5.6 KiB
Rust
use std::collections::HashMap;
|
|
|
|
fn copy_to_array(a: &mut [char; 3], b: &str) {
|
|
assert_eq!(b.len(), 3);
|
|
let mut x = 0;
|
|
for c in b.chars() {
|
|
a[x] = c;
|
|
x += 1;
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
{
|
|
let test_map = get_map_from_file("test");
|
|
assert_eq!(test_map.get("COM").unwrap().distance_to_com(&test_map), 0);
|
|
assert_eq!(test_map.get("B").unwrap().distance_to_com(&test_map), 1);
|
|
assert_eq!(test_map.get("D").unwrap().distance_to_com(&test_map), 3);
|
|
assert_eq!(test_map.get("L").unwrap().distance_to_com(&test_map), 7);
|
|
let f_parents = test_map.get("F").unwrap().parents(&test_map);
|
|
assert_eq!(f_parents, vec!["E", "D", "C", "B", "COM"]);
|
|
let l_parents = test_map.get("L").unwrap().parents(&test_map);
|
|
assert_eq!(l_parents, vec!["K", "J", "E", "D", "C", "B", "COM"]);
|
|
assert_eq!(first_common(f_parents, l_parents), "E");
|
|
let mut x: i32 = 0;
|
|
for val in test_map.values() {
|
|
x += val.distance_to_com(&test_map);
|
|
}
|
|
assert_eq!(x, 42);
|
|
}
|
|
|
|
{
|
|
let test_map2 = get_map_from_file("test2");
|
|
let you = test_map2.get("YOU").unwrap();
|
|
let san = test_map2.get("SAN").unwrap();
|
|
println!("{:?}", you);
|
|
println!("{:?}", san);
|
|
println!("{:?}", you.parents(&test_map2));
|
|
println!("{:?}", san.parents(&test_map2));
|
|
let parent = first_common(you.parents(&test_map2), san.parents(&test_map2));
|
|
println!("First common parent of YOU and SAN: '{}'", parent);
|
|
println!("Distance from YOU to {}: {}", parent, you.distance_to(&parent, &test_map2));
|
|
println!("Distance from SAN to {}: {}", parent, san.distance_to(&parent, &test_map2));
|
|
|
|
println!("[Test2] Transfers required to go from YOU to SAN: {}",
|
|
you.distance_to(&parent, &test_map2) + san.distance_to(&parent, &test_map2) - 2);
|
|
}
|
|
|
|
let map = get_map_from_file("input");
|
|
let mut x: i32 = 0;
|
|
for val in map.values() {
|
|
x += val.distance_to_com(&map);
|
|
}
|
|
println!("[Part 1] Total indirect and direct orbits: {}", x);
|
|
|
|
let you = map.get("YOU").unwrap();
|
|
let you_parents = you.parents(&map);
|
|
let san = map.get("SAN").unwrap();
|
|
let san_parents = san.parents(&map);
|
|
let common_parent = first_common(you_parents, san_parents);
|
|
println!("First common parent of YOU and SAN: '{}'", common_parent);
|
|
println!("Distance from YOU to {}: {}", common_parent, you.distance_to(&common_parent, &map));
|
|
println!("Distance from SAN to {}: {}", common_parent, san.distance_to(&common_parent, &map));
|
|
println!("[Part 2] Transfers required to go from YOU to SAN: {}",
|
|
you.distance_to(&common_parent, &map) + san.distance_to(&common_parent, &map) - 2);
|
|
}
|
|
|
|
fn first_common(a: Vec<String>, b: Vec<String>) -> String {
|
|
let mut x: Option<usize> = None;
|
|
for v_a in a.iter() {
|
|
let mut iter: usize = 0;
|
|
for v_b in b.iter() {
|
|
if v_a == v_b {
|
|
x = Some(iter);
|
|
break;
|
|
}
|
|
iter += 1;
|
|
}
|
|
if x.is_some() {
|
|
break;
|
|
}
|
|
}
|
|
return b[x.unwrap()].clone();
|
|
}
|
|
|
|
fn get_map_from_file(file: &str) -> HashMap<String, Node> {
|
|
let contents = std::fs::read_to_string(file)
|
|
.expect("Failed to read file 'input'");
|
|
let it = contents.split("\n");
|
|
let mut map: HashMap<String, Node> = HashMap::new();
|
|
for line in it {
|
|
let s = String::from(line);
|
|
s.trim();
|
|
if s.is_empty() {
|
|
break;
|
|
}
|
|
{
|
|
let values: Vec<&str> = s.split(")").collect();
|
|
//println!("Line: {}", line);
|
|
assert_eq!(values.len(), 2);
|
|
//assert_eq!(values[0].len(), 3);
|
|
//assert_eq!(values[1].len(), 3);
|
|
for v in values {
|
|
if !map.contains_key(v) {
|
|
let n = Node {
|
|
id: v.to_string(),
|
|
parent: None,
|
|
children: Vec::new(),
|
|
};
|
|
map.insert(v.to_string(), n);
|
|
}
|
|
}
|
|
}
|
|
let values: Vec<&str> = s.split(")").collect();
|
|
{
|
|
let mut node = map.get_mut(values[1]).unwrap();
|
|
if !node.parent.is_some() {
|
|
node.parent = Some(values[0].to_string());
|
|
}
|
|
}
|
|
{
|
|
let mut node = map.get_mut(values[0]).unwrap();
|
|
if !node.children.contains(&values[1].to_string()) {
|
|
node.children.push(values[1].to_string());
|
|
}
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Node {
|
|
parent: Option<String>,
|
|
id: String,
|
|
children: Vec<String>,
|
|
}
|
|
|
|
impl Node {
|
|
|
|
fn distance_to(&self, to: &str, map: &HashMap<String, Node>) -> i32 {
|
|
if self.id == to {
|
|
return 0;
|
|
}
|
|
let parent = self.parent.as_ref().unwrap().clone();
|
|
return map.get(&parent).unwrap().distance_to(to, map) + 1;
|
|
}
|
|
|
|
fn distance_to_com(&self, map: &HashMap<String, Node>) -> i32 {
|
|
return self.distance_to("COM", map);
|
|
}
|
|
|
|
fn parents(&self, map: &HashMap<String, Node>) -> Vec<String> {
|
|
let mut parents: Vec<String> = Vec::new();
|
|
if self.parent.is_some() {
|
|
parents.push(self.parent.as_ref().unwrap().clone());
|
|
let parent = map.get(&self.parent.as_ref().unwrap().clone()).unwrap();
|
|
for v in parent.parents(map) {
|
|
parents.push(v);
|
|
}
|
|
}
|
|
return parents;
|
|
}
|
|
|
|
}
|
|
|
|
impl PartialEq for Node {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.id == other.id
|
|
}
|
|
}
|