Solutions for 2022, as well as 2015-2018 and 2019 up to day 11

This commit is contained in:
Chris Alge 2023-03-12 15:20:02 +01:00
commit 1895197c49
722 changed files with 375457 additions and 0 deletions

View file

@ -0,0 +1,8 @@
[package]
name = "day24-air_duct_spelunking"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,49 @@
\--- Day 24: Air Duct Spelunking ---
----------
You've finally met your match; the doors that provide access to the roof are locked tight, and all of the controls and related electronics are inaccessible. You simply can't reach them.
The robot that cleans the air ducts, however, *can*.
It's not a very fast little robot, but you reconfigure it to be able to interface with some of the exposed wires that have been routed through the [HVAC](https://en.wikipedia.org/wiki/HVAC) system. If you can direct it to each of those locations, you should be able to bypass the security controls.
You extract the duct layout for this area from some blueprints you acquired and create a map with the relevant locations marked (your puzzle input). `0` is your current location, from which the cleaning robot embarks; the other numbers are (in *no particular order*) the locations the robot needs to visit at least once each. Walls are marked as `#`, and open passages are marked as `.`. Numbers behave like open passages.
For example, suppose you have a map like the following:
```
###########
#0.1.....2#
#.#######.#
#4.......3#
###########
```
To reach all of the points of interest as quickly as possible, you would have the robot take the following path:
* `0` to `4` (`2` steps)
* `4` to `1` (`4` steps; it can't move diagonally)
* `1` to `2` (`6` steps)
* `2` to `3` (`2` steps)
Since the robot isn't very fast, you need to find it the *shortest route*. This path is the fewest steps (in the above example, a total of `14`) required to start at `0` and then visit every other location at least once.
Given your actual map, and starting from location `0`, what is the *fewest number of steps* required to visit every non-`0` number marked on the map at least once?
Your puzzle answer was `462`.
\--- Part Two ---
----------
Of course, if you leave the cleaning robot somewhere weird, someone is bound to notice.
What is the fewest number of steps required to start at `0`, visit every non-`0` number marked on the map at least once, and then *return to `0`*?
Your puzzle answer was `676`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, all that is left is for you to [admire your Advent calendar](/2016).
If you still want to see it, you can [get your puzzle input](24/input).

View file

@ -0,0 +1,218 @@
warning: unused variable: `challenge_input`
--> src/lib.rs:137:13
|
137 | let challenge_input = read_file("tests/challenge_input");
| ^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_challenge_input`
|
= note: `#[warn(unused_variables)]` on by default
warning: `day24-air_duct_spelunking` (lib test) generated 1 warning
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/day24_air_duct_spelunking-a142b0dc6356a23c)
[src/lib.rs:27] &distances = {
(
(
9,
1,
),
(
1,
3,
),
): 10,
(
(
9,
3,
),
(
1,
3,
),
): 8,
(
(
9,
3,
),
(
3,
1,
),
): 8,
(
(
1,
1,
),
(
1,
3,
),
): 2,
(
(
3,
1,
),
(
1,
3,
),
): 4,
(
(
1,
3,
),
(
9,
3,
),
): 8,
(
(
1,
1,
),
(
9,
1,
),
): 8,
(
(
9,
1,
),
(
3,
1,
),
): 6,
(
(
3,
1,
),
(
9,
3,
),
): 8,
(
(
1,
1,
),
(
3,
1,
),
): 2,
(
(
3,
1,
),
(
1,
1,
),
): 2,
(
(
1,
3,
),
(
9,
1,
),
): 10,
(
(
9,
1,
),
(
9,
3,
),
): 2,
(
(
9,
1,
),
(
1,
1,
),
): 8,
(
(
1,
3,
),
(
1,
1,
),
): 2,
(
(
9,
3,
),
(
9,
1,
),
): 2,
(
(
3,
1,
),
(
9,
1,
),
): 6,
(
(
1,
3,
),
(
3,
1,
),
): 4,
(
(
1,
1,
),
(
9,
3,
),
): 10,
(
(
9,
3,
),
(
1,
1,
),
): 10,
}
thread 'tests::test_sample' panicked at 'assertion failed: `(left == right)`
left: `(18, 24)`,
right: `(14, 24)`', src/lib.rs:132:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: test failed, to rerun pass `--lib`

View file

@ -0,0 +1,144 @@
use std::collections::{HashSet, HashMap};
#[derive(PartialEq, Eq, Hash)]
enum Tile{ Wall, Open, Loc(u8) }
impl Tile {
fn parse(byte: u8) -> Self {
match byte {
b'#' => Self::Wall,
b'.' => Self::Open,
n @ b'0'..=b'9' => Self::Loc(n-b'0'),
_ => panic!("Unexpected Byte: {byte}"),
}
}
}
type Coordinates = (usize, usize);
type Route = (Coordinates, Coordinates);
pub fn run(input: &str) -> (usize, usize) {
let maze: Vec<Vec<Tile>> = input.lines().map(|l| l.bytes().map(Tile::parse).collect()).collect();
let to_visit: Vec<_> = maze.iter().enumerate().flat_map(|(row, tiles)|tiles.iter().enumerate().filter(|(_, t)| matches!(t, Tile::Loc(_)) && **t != Tile::Loc(0)).map(move |(col, _)| (col, row))).collect();
let start = maze.iter()
.enumerate()
.find(|(_, tiles)| tiles.contains(&Tile::Loc(0)))
.map(|(row, tiles)| (tiles.iter()
.position(|t| t == &Tile::Loc(0))
.unwrap(), row)).unwrap();
let distances = get_distance_network(start, &to_visit, &maze);
let first = salesman(start, &to_visit, &distances, false);
let second = salesman(start, &to_visit, &distances, true);
(first, second)
}
fn salesman(start: Coordinates, to_visit: &[Coordinates], distances: &HashMap<Route, usize>, returning: bool) -> usize {
let initial = (start, to_visit.to_vec());
let mut open_set = HashSet::from([initial.clone()]);
let mut costs = HashMap::from([(initial.clone(), 0)]);
let mut estimated_cost = HashMap::from([(initial, to_visit.len() * to_visit.iter().map(|dest| distances.get(&(start, *dest)).unwrap()).min().unwrap())]);
while !open_set.is_empty() {
let current = open_set.iter().min_by_key(|state| estimated_cost.get(state).unwrap()).unwrap().clone();
let current_costs = *costs.get(&current).unwrap();
open_set.remove(&current);
if current.1.is_empty() {
if returning {
return current_costs + distances.get(&(start, current.0)).unwrap();
} else {
return current_costs;
}
}
for next in &current.1 {
let new_costs = current_costs + distances.get(&(current.0, *next)).unwrap();
let min_return_cost = current.1.iter().map(|node| distances.get(&(*node, start)).unwrap()).min().unwrap();
let mut next_to_visit = current.1.clone();
next_to_visit.remove(next_to_visit.iter().position(|d| d==next).unwrap());
if new_costs < *costs.get(&(*next, next_to_visit.clone())).unwrap_or(&usize::MAX) {
let mut next_estimated = if next_to_visit.is_empty() { 0 } else {
*next_to_visit.iter().map(|dest| distances.get(&(*next, *dest)).unwrap()).max().unwrap()
};
if returning {
next_estimated += min_return_cost;
}
open_set.insert((*next, next_to_visit.to_vec()));
costs.insert((*next, next_to_visit.to_vec()), new_costs);
estimated_cost.insert((*next, next_to_visit.to_vec()), new_costs + next_estimated);
}
}
}
panic!("Exhausted all ways but found no solution")
}
fn get_distance_network(start: Coordinates, other: &[Coordinates], maze: &[Vec<Tile>]) -> HashMap<Route, usize> {
let mut network = HashMap::new();
let mut combined = other.to_vec();
combined.push(start);
for dest in get_network_from(start, &combined, maze) {
network.insert((start, dest.0), dest.1);
network.insert((dest.0, start), dest.1);
}
for node in other {
let other_network = get_network_from(*node, other, maze);
for dest in other_network {
network.insert((*node, dest.0), dest.1);
}
}
network
}
fn get_network_from(start: Coordinates, other: &[Coordinates], maze: &[Vec<Tile>]) -> HashMap<Coordinates, usize> {
let mut network = HashMap::new();
let mut visited = HashSet::from([start]);
let mut visited_last_step = HashSet::from([start]);
let mut depth = 1;
while network.len() < other.len()-1 {
let mut visited_this_step = HashSet::new();
for node in &visited_last_step {
for neighbour in neighbours(*node, maze) {
if !visited.contains(&neighbour) {
visited.insert(neighbour);
visited_this_step.insert(neighbour);
if other.contains(&neighbour) {
network.insert(neighbour, depth);
}
}
}
}
depth += 1;
std::mem::swap(&mut visited_last_step, &mut visited_this_step);
}
network
}
fn neighbours((x, y): Coordinates, maze: &[Vec<Tile>]) -> Vec<Coordinates> {
let mut res = Vec::new();
for direction in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let coords =((x as isize + direction.0) as usize, (y as isize + direction.1) as usize);
if maze[coords.1][coords.0] != Tile::Wall {
res.push(coords);
}
}
res
}
#[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), (14, 20));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), (462, 676));
}
}

View file

@ -0,0 +1,41 @@
#########################################################################################################################################################################################
#.#.....#.........#.....#.......#.#...........#...#.....................#...................#.....#.......#.#...#...................#...#...........#...#...#...#...#...#...#.....#...#.#
#.###.#.#.###.#.#.#.#.#.#########.#.#.###.#.#.#.###.#.#.#.#####.#.###.###.#.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#.#.#.###.###.#.#.#.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#
#.#...#.#...#...#...#.........#...#...#...#.............#.......#.....#.....#...#.#.......#.......#.........#.#.#...#...#...#.....#...#...#.#.#.#..3#.....#.........#.#...#.....#.#...#.#
#.#.#.#.#.#.#.#.#.#.#.###.###.#.#####.#.#.#####.#.###.#####.#.###.#.###.#.###.#####.###.###.#.###.#.#.#.###.#####.###.###.###.#.###.#.#####.#.###.#.#.###.###.#.###.#.###.#.###.###.#.#.#
#.....#.....#...#.....#...#.#.#.#...#...#...#.#...#...#.......#...#.....#...#.....#.......#.#...#.....#...#.#...#.....#.....#.#.#...#.#.......#.......#...#...#.#.#.#.#.#...#.......#.#.#
#.###.#.###.#.###.#.#.#.#.#.#####.#.#.#.#####.#.#.#.#.#.#.#.###.#.#.###.#.#.#.###.###.###.#.###.#.#.#.###.#.#.###.#.#####.#.#.#.#.#.#.#.#####.#.#.#.###.#.#.#.###.#.#.#.###.#.#######.#.#
#...#.#.#5#.#.........#.....#.....#.#.#.#...........#.#.....#.#...#.........#.....#...#.#...#.#.#.#...#.....#...#.#.....#...#...#.#.#...#.#.....#...#...#.....#.......#...#...#.....#...#
#.#.#.###.#.#########.###.#.###.#.#.#.###.#.#######.#.#.#.#.#.#.#######.###.#.#.#.#.###.#.###.#.#.#.###.#.#####.###.###.###.#.#.#.#.#.#.#.###.#####.#######.#.#.#.###.#.#.###.#.###.###.#
#...#.#.......#.#.......#.#...#...#.....#.#.#.....#.#...#...#...#.....#.....#.#...#.#.........#.....#...........#.......#.....#...#.#.....#.......#.#...#...#.#.......#.#.#.#.#.........#
###.#.#.###.#.#.#.#.#.#.#.#.#.#.#######.#.#.#.#.###.#.#.###.#.#.#.#.#.#.#####.#####.#.#.#.###.#.#####.#.#.#.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#.#.#.#.#.#####.###.#######.#
#.#...#.#...#.#.....#...#...#...#.....#.........#.............#.......#.............#.........#.......#...#...#...#.......#.....#.......#...#.....#.....#.........#.#.#...#.#...#.....#6#
#.#.#.#.###.#.#.###.#.#.#.#.#.###.#.#.#.#.#####.#.#.###.#.###.#.#.#######.#.#####.#.#######.#####.#######.#.###.#.#####.#.#.#.#.#.#####.#.#.#.#.#.#######.###.#.###.#.#.#.#.#.#.#.#.#.#.#
#...#.#...#.#...........#...#.......#...#...#.......#...#.#.....#.#.................#...#...#.#.....#.....#.#.......#...#.....#...#.#...#.......#.#.#...#.......#...#.#.#.........#.....#
#####.###.#.###.#####.###.#.#.#.#####.#.###.#.#.#####.#.#.#.#.#.###.#####.###.#.#####.###.#.#.#.#.#.###.###.#######.#.#.#.#.#.#.#.#.###.###.###.###.#.#.#.#.#####.#.#.###.#.#####.###.###
#...#.#.........#.#...#.#...........#.#...#...#.#...#...#...#.......#...#...#...............................#.....#...#...#.....#...#.#.#.#...#.#.......#.....#.....#.#.#...#...#...#...#
###.#.#.#########.#.###.#.#.###.#######.#.###.#.#.###.#.#.###.#####.###.#.#.#####.#.#.#.#.###.###.#.#.#.#.#.#.#######.#.#.#.###.###.#.#.#.#.#.###.###.###.###.#####.#.#.#.#.###.#.#.#.#.#
#.#...#.#.#.#.......#...#.....#.#...#...#.....#.............#.#...#.#...#.#.......#.......#...................#.....#.#.....#.#...#.#...#.#...#...#...#...#.....#.#...#.........#...#...#
#.#.#.###.#.#########.#.#.#.#.#.#.#.#.###.#.###.#.#.#.#.#######.#.#####.#####.#.#.###.###.#.#.#.###.#####.###.#.#.#.#.#.#.###.#####.#####.#.#.#####.#######.###.#.#.#.#.#.#####.###.#.#.#
#...#.#.....#.#.#4#.#...#...#.........#.#.#...#...#.#.#.....#...#.#.....#.....#.......#...#.#.#.......#...#.#...#.....#.#.....#.........#.#...#.........#...#.#...#...............#.#...#
#####.#.#.###.#.#.#.#.#.###.#.#.###.###.#.#.#.#.#.#.###.###.#.#.#.#.#######.###.###.#.###.#.#####.#.###.#.#.###.#####.#.#######.#.#######.###.#.#.###.#.#.###.#.#########.#.###.#.#.###.#
#...#.....#.....#.......#.#...#.#.#.#.....#...#.#.#...........#.#.............#.#.......#.#.#...........#.............#.....#.#.......#...#.....#.#...#.#...#.#.........#.#...#.#...#...#
#.#.#.###.#########.#.#.#.#.#.###.###.###.#######.#.#.###.#.#.#.#.###.#.#.#.#.###.#####.###.#####.#.###.#.#.###.#.#.#.#####.#.#.#.#.###.#.#.#.###.#.###.#.#.#.#.###.###.#.#.#######.#.###
#...#.....#.#.......#...#.#...#.......#.......#...#.#...#...#.#.#...........#...#.......#...#.......#.#.....#.....#...#.......#...#.........#.....#.#.#.#.#...#.#.........#...........#.#
#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.#.#.#.#.#.#.#.###.###.###.#.#.#.#####.###.#.#.#########.#.#.###.#.#.#.###.###.#.#.###.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.###.#.###.#.#.#.#####.#.#.#.#
#.#.....#.#...#.#.#.#.#...#.......#.#...#.#.#.#...#...#.......#.......#...#...#.#...#.....#.#...#...#...#.........#...#.#.#.....#.#.....#.....#.............#...#.......#...........#...#
#.#.#.#.#.#.###.###.###.###.#.###.#.#.#.#.#.#.#.#.#.#######.#####.#.#.#####.#.#.###.#.#.#####.#.#####.#.#.#.#.#.#.###.#.###.#.###.#.#.###.###.#.#.#.#.#.###.#.#.#.###.###.#.#.#####.#####
#...#.........#.....#.#.....#.....#.#...#.#...#...........#.#.......#.........#...............#.#...#...#.#...#.....#.#.#.....#...#.......#...#.....#...#...#.....#...#...#...#7#.......#
#.#.#.###.#######.###.#.#####.#.###.#.###.#.#######.#.#.#.#.###.###.#.#.#####.#.#.#.###.#.#.###.#.#.#####.#.#.###.#.#.#.#.#.###.#.#.#.###.#.#.###.#####.#.###.#.###.#.###.#.#.#.#######.#
#...#.#.............#.#...#0..#.#...........#.#.............#...#...#...#.......#.....#...#.......#...#.....#.....#.#.#.#...#.#.#.#...#...#...#.....#.#.#...........#.....#.....#.#.....#
###.#.###.#.#.#.#.#.#.###.#.#.#.###.###.#####.#.#####.###.#.#.#.#.#####.#.#.#.#####.#####.#.#.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#.#####.#.###.#####.#.#.###.#######.#.#.#.#####.#.#.#.#
#.#.....#...#.......#.....#.....#...#.....#...........#...#.....#.#.....#.......#.....#.....#.............#.#...#.....#.#.........#...#...#.#.............#...#...#...#.#...#.#.......#.#
#.#.#.#.#.###.###.###.#.#.#.#######.#.#.#.#####.#.###.#.###.#.#.#.#.###.#.###.#.#.###.#.#.#.#########.#.#.#.###.#.#.###.#.#######.#.###.#.#.#.#.#.#.###.#.#.#.###.#.#.#.#####.#.#.###.###
#.....#...#.......#.....#...#.#.....#...#.........#...#.....#.#...#.......#...............#.#.......#.......#.#...........#.....#.......#.#.#.#.#...#.......#.....#.....#...#.......#...#
#.###.###.#.#######.#.#.#.#.#.#.#.#.###.#.#######.#.###.#.#####.###.#.###.###.#####.#.###.###.#.#.#.#####.#.#.#.#########.#.#.#.#####.#.#.#.###.#.###.#.###.#.###.###.#.#.#.#.#.#.#.#.#.#
#.#.#.......#.#.#...#.....#.....#.#...#.....#...#.....#.#.#...........#...#...#...#.....#...#.......#.#.....#.........#...#.#...........#.#.#...#...#......1#.....#...#.#...#...#...#...#
#.#.#.#.#####.#.#.###.#####.#####.#.#.###.###.#.#####.###.#.#.#.#.#####.###.###.#.#.###.###.#######.#.###.#.#.###.#.#.#.###.#.###########.#.#.###.#######.#######.#.###.###.#.#.#.###.#.#
#...#.........#.....#...#.....#.....#...#.....#.......#.#...#...#.#.......#.....#...#.........#.....#...#.#.#...............#.............#.......#.........#.........#...........#.....#
#.#.#.###.#.#.#.###.###.#.#####.#####.#.###.#.###.#.#.#.###.#.#####.#.###.#.#.#.#.#.#.#.###.###.###.###.#.#.#.#.#.#.#####.###.#.#.#######.#.#.#.###.#.###.#.#.#.###.#####.###.###.#.#.###
#.........#.....#.......#....2#.........#.....#.....#.#.......#.#.#.......#.#...#...........#.#.#...#...#.#...#.....#.....#.#.#.#.#.......#...#.#.#.#.........#.#.........#.#...#...#.#.#
#########################################################################################################################################################################################

View file

@ -0,0 +1,5 @@
###########
#0.1.....2#
#.#######.#
#4.......3#
###########