Solutions for 2022, as well as 2015-2018 and 2019 up to day 11
This commit is contained in:
commit
1895197c49
722 changed files with 375457 additions and 0 deletions
8
2019/day06_universal_orbit_map/Cargo.toml
Normal file
8
2019/day06_universal_orbit_map/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "day06_universal_orbit_map"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
133
2019/day06_universal_orbit_map/challenge.txt
Normal file
133
2019/day06_universal_orbit_map/challenge.txt
Normal file
|
@ -0,0 +1,133 @@
|
|||
You've landed at the Universal Orbit Map facility on Mercury. Because navigation in space often involves transferring between orbits, the orbit maps here are useful for finding efficient routes between, for example, you and Santa. You download a map of the local orbits (your puzzle input).
|
||||
|
||||
Except for the universal Center of Mass (`COM`), every object in space is in orbit around exactly one other object. An [orbit](https://en.wikipedia.org/wiki/Orbit) looks roughly like this:
|
||||
|
||||
```
|
||||
\
|
||||
\
|
||||
|
|
||||
|
|
||||
AAA--> o o <--BBB
|
||||
|
|
||||
|
|
||||
/
|
||||
/
|
||||
|
||||
```
|
||||
|
||||
In this diagram, the object `BBB` is in orbit around `AAA`. The path that `BBB` takes around `AAA` (drawn with lines) is only partly shown. In the map data, this orbital relationship is written `AAA)BBB`, which means "`BBB` is in orbit around `AAA`".
|
||||
|
||||
Before you use your map data to plot a course, you need to make sure it wasn't corrupted during the download. To verify maps, the Universal Orbit Map facility uses *orbit count checksums* - the total number of *direct orbits* (like the one shown above) and *indirect orbits*.
|
||||
|
||||
Whenever `A` orbits `B` and `B` orbits `C`, then `A` *indirectly orbits* `C`. This chain can be any number of objects long: if `A` orbits `B`, `B` orbits `C`, and `C` orbits `D`, then `A` indirectly orbits `D`.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
```
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
|
||||
```
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
```
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I
|
||||
|
||||
```
|
||||
|
||||
In this visual representation, when two objects are connected by a line, the one on the right directly orbits the one on the left.
|
||||
|
||||
Here, we can count the total number of orbits as follows:
|
||||
|
||||
* `D` directly orbits `C` and indirectly orbits `B` and `COM`, a total of `3` orbits.
|
||||
* `L` directly orbits `K` and indirectly orbits `J`, `E`, `D`, `C`, `B`, and `COM`, a total of `7` orbits.
|
||||
* `COM` orbits nothing.
|
||||
|
||||
The total number of direct and indirect orbits in this example is `*42*`.
|
||||
|
||||
*What is the total number of direct and indirect orbits* in your map data?
|
||||
|
||||
Your puzzle answer was `417916`.
|
||||
|
||||
\--- Part Two ---
|
||||
----------
|
||||
|
||||
Now, you just need to figure out how many *orbital transfers* you (`YOU`) need to take to get to Santa (`SAN`).
|
||||
|
||||
You start at the object `YOU` are orbiting; your destination is the object `SAN` is orbiting. An orbital transfer lets you move from any object to an object orbiting or orbited by that object.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
```
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
||||
|
||||
```
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
```
|
||||
YOU
|
||||
/
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
|
||||
```
|
||||
|
||||
In this example, `YOU` are in orbit around `K`, and `SAN` is in orbit around `I`. To move from `K` to `I`, a minimum of `4` orbital transfers are required:
|
||||
|
||||
* `K` to `J`
|
||||
* `J` to `E`
|
||||
* `E` to `D`
|
||||
* `D` to `I`
|
||||
|
||||
Afterward, the map of orbits looks like this:
|
||||
|
||||
```
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
\
|
||||
YOU
|
||||
|
||||
```
|
||||
|
||||
*What is the minimum number of orbital transfers required* to move from the object `YOU` are orbiting to the object `SAN` is orbiting? (Between the objects they are orbiting - *not* between `YOU` and `SAN`.)
|
||||
|
||||
Your puzzle answer was `523`.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: \*\*
|
||||
|
||||
At this point, you should [return to your Advent calendar](/2019) and try another puzzle.
|
||||
|
||||
If you still want to see it, you can [get your puzzle input](6/input).
|
105
2019/day06_universal_orbit_map/src/lib.rs
Normal file
105
2019/day06_universal_orbit_map/src/lib.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Orbit {
|
||||
trabant_id: usize,
|
||||
center_id: usize,
|
||||
}
|
||||
|
||||
pub fn run(input: &str) -> (usize, usize) {
|
||||
let graph: Vec<_> = graph_from(input);
|
||||
let first = count_direct_and_indirect_orbits(&graph);
|
||||
let common_orbit = get_common_center(&graph, 1, 2);
|
||||
|
||||
let second = distance(&graph, common_orbit, 1) + distance(&graph, common_orbit, 2) - 2;
|
||||
(first, second)
|
||||
}
|
||||
|
||||
fn graph_from(map: &str) -> Vec<Orbit> {
|
||||
let mut bodies = HashMap::from([("COM", 0), ("YOU", 1), ("SAN", 2)]);
|
||||
let mut graph: Vec<Orbit> = Vec::new();
|
||||
for line in map.lines() {
|
||||
let (center, trabant) = line.split_once(')').unwrap();
|
||||
let mut bodies_len = bodies.len();
|
||||
let center_id = *bodies.entry(center).or_insert(bodies_len);
|
||||
bodies_len = bodies.len();
|
||||
let trabant_id = *bodies.entry(trabant).or_insert(bodies_len);
|
||||
graph.push(Orbit { center_id, trabant_id } );
|
||||
}
|
||||
graph.sort();
|
||||
graph
|
||||
}
|
||||
|
||||
fn count_direct_and_indirect_orbits(graph: &[Orbit]) -> usize {
|
||||
graph.iter().map(|o| count_upstream_bodies(graph, o.trabant_id)).sum()
|
||||
}
|
||||
|
||||
fn count_upstream_bodies(graph: &[Orbit], trabant_id: usize) -> usize {
|
||||
let trabant_idx = graph.binary_search_by_key(&trabant_id, |o| o.trabant_id).unwrap();
|
||||
if graph[trabant_idx].center_id == 0 {
|
||||
1
|
||||
} else {
|
||||
1 + count_upstream_bodies(graph, graph[trabant_idx].center_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_common_center(graph: &[Orbit], lhs: usize, rhs: usize) -> usize {
|
||||
if lhs == rhs {
|
||||
return lhs;
|
||||
}
|
||||
if is_orbited_by(graph, lhs, rhs) {
|
||||
return lhs;
|
||||
} else if is_orbited_by(graph, rhs, lhs) {
|
||||
return rhs;
|
||||
}
|
||||
let trabant_idx = graph.binary_search_by_key(&lhs, |o| o.trabant_id).unwrap();
|
||||
get_common_center(graph, graph[trabant_idx].center_id, rhs)
|
||||
}
|
||||
|
||||
fn is_orbited_by(graph: &[Orbit], inner: usize, outer: usize) -> bool {
|
||||
if inner == outer {
|
||||
true
|
||||
} else {
|
||||
let outer_idx = graph.binary_search_by_key(&outer, |o| o.trabant_id).unwrap();
|
||||
if graph[outer_idx].center_id == 0 {
|
||||
false
|
||||
} else {
|
||||
is_orbited_by(graph, inner, graph[outer_idx].center_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn distance(graph: &[Orbit], inner: usize, outer: usize) -> usize {
|
||||
if inner == outer {
|
||||
0
|
||||
} else {
|
||||
let outer_idx = graph.binary_search_by_key(&outer, |o| o.trabant_id).unwrap();
|
||||
if graph[outer_idx].center_id == 0 {
|
||||
usize::MAX
|
||||
} else {
|
||||
distance(graph, inner, graph[outer_idx].center_id) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
fn read_file(name: &str) -> String {
|
||||
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let sample_input = read_file("tests/sample_input");
|
||||
assert_eq!(run(&sample_input), (54, 4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_challenge() {
|
||||
let challenge_input = read_file("tests/challenge_input");
|
||||
assert_eq!(run(&challenge_input), (417916, 523));
|
||||
}
|
||||
}
|
2113
2019/day06_universal_orbit_map/tests/challenge_input
Normal file
2113
2019/day06_universal_orbit_map/tests/challenge_input
Normal file
File diff suppressed because it is too large
Load diff
13
2019/day06_universal_orbit_map/tests/sample_input
Normal file
13
2019/day06_universal_orbit_map/tests/sample_input
Normal file
|
@ -0,0 +1,13 @@
|
|||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
Loading…
Add table
Add a link
Reference in a new issue