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
2018/day22_mode_maze/Cargo.toml
Normal file
8
2018/day22_mode_maze/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "day22_mode_maze"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
351
2018/day22_mode_maze/challenge.txt
Normal file
351
2018/day22_mode_maze/challenge.txt
Normal file
|
@ -0,0 +1,351 @@
|
|||
This is it, your final stop: the year -483. It's snowing and dark outside; the only light you can see is coming from a small cottage in the distance. You make your way there and knock on the door.
|
||||
|
||||
A portly man with a large, white beard answers the door and invites you inside. For someone living near the North Pole in -483, he must not get many visitors, but he doesn't act surprised to see you. Instead, he offers you some milk and cookies.
|
||||
|
||||
After talking for a while, he asks a favor of you. His friend hasn't come back in a few hours, and he's not sure where he is. Scanning the region briefly, you discover one life signal in a cave system nearby; his friend must have taken shelter there. The man asks if you can go there to retrieve his friend.
|
||||
|
||||
The cave is divided into square *regions* which are either dominantly *rocky*, *narrow*, or *wet* (called its *type*). Each region occupies exactly one *coordinate* in `X,Y` format where `X` and `Y` are integers and zero or greater. (Adjacent regions can be the same type.)
|
||||
|
||||
The scan (your puzzle input) is not very detailed: it only reveals the *depth* of the cave system and the *coordinates of the target*. However, it does not reveal the type of each region. The mouth of the cave is at `0,0`.
|
||||
|
||||
The man explains that due to the unusual geology in the area, there is a method to determine any region's type based on its *erosion level*. The erosion level of a region can be determined from its *geologic index*. The geologic index can be determined using the first rule that applies from the list below:
|
||||
|
||||
* The region at `0,0` (the mouth of the cave) has a geologic index of `0`.
|
||||
* The region at the coordinates of the target has a geologic index of `0`.
|
||||
* If the region's `Y` coordinate is `0`, the geologic index is its `X` coordinate times `16807`.
|
||||
* If the region's `X` coordinate is `0`, the geologic index is its `Y` coordinate times `48271`.
|
||||
* Otherwise, the region's geologic index is the result of multiplying the erosion *levels* of the regions at `X-1,Y` and `X,Y-1`.
|
||||
|
||||
A region's *erosion level* is its *geologic index* plus the cave system's *depth*, all [modulo](https://en.wikipedia.org/wiki/Modulo_operation) `20183`. Then:
|
||||
|
||||
* If the *erosion level modulo `3`* is `0`, the region's type is *rocky*.
|
||||
* If the *erosion level modulo `3`* is `1`, the region's type is *wet*.
|
||||
* If the *erosion level modulo `3`* is `2`, the region's type is *narrow*.
|
||||
|
||||
For example, suppose the cave system's depth is `510` and the target's coordinates are `10,10`. Using `%` to represent the modulo operator, the cavern would look as follows:
|
||||
|
||||
* At `0,0`, the geologic index is `0`. The erosion level is `(0 + 510) % 20183 = 510`. The type is `510 % 3 = 0`, *rocky*.
|
||||
* At `1,0`, because the `Y` coordinate is `0`, the geologic index is `1 * 16807 = 16807`. The erosion level is `(16807 + 510) % 20183 = 17317`. The type is `17317 % 3 = 1`, *wet*.
|
||||
* At `0,1`, because the `X` coordinate is `0`, the geologic index is ` 1 * 48271 = 48271`. The erosion level is `(48271 + 510) % 20183 = 8415`. The type is `8415 % 3 = 0`, *rocky*.
|
||||
* At `1,1`, neither coordinate is `0` and it is not the coordinate of the target, so the geologic index is the erosion level of `0,1` (`8415`) times the erosion level of `1,0` (`17317`), `8415 * 17317 = 145722555`. The erosion level is `(145722555 + 510) % 20183 = 1805`. The type is `1805 % 3 = 2`, *narrow*.
|
||||
* At `10,10`, because they are the target's coordinates, the geologic index is `0`. The erosion level is `(0 + 510) % 20183 = 510`. The type is `510 % 3 = 0`, *rocky*.
|
||||
|
||||
Drawing this same cave system with rocky as `.`, wet as `=`, narrow as `|`, the mouth as `M`, the target as `T`, with `0,0` in the top-left corner, `X` increasing to the right, and `Y` increasing downward, the top-left corner of the map looks like this:
|
||||
|
||||
```
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
```
|
||||
|
||||
Before you go in, you should determine the *risk level* of the area. For the rectangle that has a top-left corner of region `0,0` and a bottom-right corner of the region containing the target, add up the risk level of each individual region: `0` for rocky regions, `1` for wet regions, and `2` for narrow regions.
|
||||
|
||||
In the cave system above, because the mouth is at `0,0` and the target is at `10,10`, adding up the risk level of all regions with an `X` coordinate from `0` to `10` and a `Y` coordinate from `0` to `10`, this total is `*114*`.
|
||||
|
||||
*What is the total risk level for the smallest rectangle that includes `0,0` and the target's coordinates?*
|
||||
|
||||
Your puzzle answer was `11810`.
|
||||
|
||||
\--- Part Two ---
|
||||
----------
|
||||
|
||||
Okay, it's time to go rescue the man's friend.
|
||||
|
||||
As you leave, he hands you some tools: a *torch* and some *climbing gear*. You can't equip both tools at once, but you can choose to use *neither*.
|
||||
|
||||
Tools can only be used in certain regions:
|
||||
|
||||
* In *rocky* regions, you can use the *climbing gear* or the *torch*. You cannot use *neither* (you'll likely slip and fall).
|
||||
* In *wet* regions, you can use the *climbing gear* or *neither* tool. You cannot use the *torch* (if it gets wet, you won't have a light source).
|
||||
* In *narrow* regions, you can use the *torch* or *neither* tool. You cannot use the *climbing gear* (it's too bulky to fit).
|
||||
|
||||
You start at `0,0` (the mouth of the cave) with *the torch equipped* and must reach the target coordinates as quickly as possible. The regions with negative `X` or `Y` are solid rock and cannot be traversed. The fastest route might involve entering regions beyond the `X` or `Y` coordinate of the target.
|
||||
|
||||
You can *move to an adjacent region* (up, down, left, or right; never diagonally) if your currently equipped tool allows you to enter that region. Moving to an adjacent region takes *one minute*. (For example, if you have the *torch* equipped, you can move between *rocky* and *narrow* regions, but cannot enter *wet* regions.)
|
||||
|
||||
You can *change your currently equipped tool or put both away* if your new equipment would be valid for your current region. Switching to using the *climbing gear*, *torch*, or *neither* always takes *seven minutes*, regardless of which tools you start with. (For example, if you are in a *rocky* region, you can switch from the *torch* to the *climbing gear*, but you cannot switch to *neither*.)
|
||||
|
||||
Finally, once you reach the target, you need the *torch* equipped before you can find him in the dark. The target is always in a *rocky* region, so if you arrive there with *climbing gear* equipped, you will need to spend seven minutes switching to your torch.
|
||||
|
||||
For example, using the same cave system as above, starting in the top left corner (`0,0`) and moving to the bottom right corner (the target, `10,10`) as quickly as possible, one possible route is as follows, with your current position marked `X`:
|
||||
|
||||
```
|
||||
Initially:
|
||||
X=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Down:
|
||||
M=.|=.|.|=.|=|=.
|
||||
X|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Right:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.X=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Switch from using the torch to neither tool:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.X=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Right 3:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|X|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Switch from using neither tool to the climbing gear:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|X|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Down 7:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..X==..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Right:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..=X=..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Down 3:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||.X.|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Right:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||..X|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Down:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.X..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Right 4:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===T===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=X||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Up 2:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===X===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
Switch from using the climbing gear to the torch:
|
||||
M=.|=.|.|=.|=|=.
|
||||
.|=|=|||..|.=...
|
||||
.==|....||=..|==
|
||||
=.|....|.==.|==.
|
||||
=|..==...=.|==..
|
||||
=||.=.=||=|=..|=
|
||||
|.=.===|||..=..|
|
||||
|..==||=.|==|===
|
||||
.=..===..=|.|||.
|
||||
.======|||=|=.|=
|
||||
.===|=|===X===||
|
||||
=|||...|==..|=.|
|
||||
=.=|=.=..=.||==|
|
||||
||=|=...|==.=|==
|
||||
|=.=||===.|||===
|
||||
||.|==.|.|.||=||
|
||||
|
||||
```
|
||||
|
||||
This is tied with other routes as the *fastest way to reach the target*: `*45*` minutes. In it, `21` minutes are spent switching tools (three times, seven minutes each) and the remaining `24` minutes are spent moving.
|
||||
|
||||
*What is the fewest number of minutes you can take to reach the target?*
|
||||
|
||||
Your puzzle answer was `1015`.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: \*\*
|
||||
|
||||
At this point, you should [return to your Advent calendar](/2018) and try another puzzle.
|
||||
|
||||
If you still want to see it, you can [get your puzzle input](22/input).
|
157
2018/day22_mode_maze/src/lib.rs
Normal file
157
2018/day22_mode_maze/src/lib.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
use std::collections::{HashMap, HashSet, BTreeSet};
|
||||
|
||||
struct Regions {
|
||||
erosion_levels: HashMap<(usize, usize), usize>,
|
||||
target: (usize, usize),
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl Regions {
|
||||
fn get_geo_index(&mut self, (x, y): (usize, usize)) -> usize {
|
||||
if [(0, 0), self.target].contains(&(x, y)) {
|
||||
0
|
||||
} else if y == 0 {
|
||||
x * 16807
|
||||
} else if x == 0 {
|
||||
y * 48271
|
||||
} else {
|
||||
self.get_erosion_level((x-1, y)) * self.get_erosion_level((x, y-1))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_erosion_level(&mut self, coordinates: (usize, usize)) -> usize {
|
||||
if let Some(res) = self.erosion_levels.get(&coordinates) {
|
||||
*res
|
||||
} else {
|
||||
let res = (self.get_geo_index(coordinates) + self.depth) % 20183;
|
||||
self.erosion_levels.insert(coordinates, res);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_score(&mut self, coordinates: (usize, usize)) -> usize {
|
||||
self.get_erosion_level(coordinates)%3
|
||||
}
|
||||
|
||||
fn get_neighbours(&mut self, current: NavigationState) -> Vec<NavigationState> {
|
||||
let (x, y) = current.coordinates;
|
||||
|
||||
// Determine the other tool allowed in this terrain:
|
||||
// Their numbers all add up to 3 (0+1+2). Substract the one we already have equiped (we
|
||||
// make sure this is allowed below) and the one not allowed here (which equals the terrain
|
||||
// score) and we have left the allowed one.
|
||||
let other_tool = 3-current.tool-self.get_type_score(current.coordinates);
|
||||
|
||||
// We can always stay in place and switch tools.
|
||||
let mut res = Vec::from([NavigationState{
|
||||
coordinates: (current.coordinates),
|
||||
tool: other_tool,
|
||||
time_elapsed: current.time_elapsed+7,
|
||||
projected_total: current.time_elapsed+7 + x.abs_diff(self.target.0) + y.abs_diff(self.target.1) + 7*other_tool.abs_diff(1),
|
||||
}]);
|
||||
|
||||
// For all directions (barring negative x and y): If our current tool is allowed there, we
|
||||
// can go there in 1 minute.
|
||||
if x>0 && self.get_type_score((x-1, y)) != current.tool {
|
||||
res.push(NavigationState { coordinates: (x-1, y), tool: current.tool, time_elapsed: current.time_elapsed+1, projected_total: current.time_elapsed+1 + (x-1).abs_diff(self.target.0) + y.abs_diff(self.target.1) + 7*(current.tool.abs_diff(1)) });
|
||||
}
|
||||
if self.get_type_score((x+1, y)) != current.tool {
|
||||
res.push(NavigationState { coordinates: (x+1, y), tool: current.tool, time_elapsed: current.time_elapsed+1, projected_total: current.time_elapsed+1 + (x+1).abs_diff(self.target.0) + y.abs_diff(self.target.1) + 7*(current.tool.abs_diff(1)) });
|
||||
}
|
||||
if y>0 && self.get_type_score((x, y-1)) != current.tool {
|
||||
res.push(NavigationState { coordinates: (x, y-1), tool: current.tool, time_elapsed: current.time_elapsed+1, projected_total: current.time_elapsed+1 + x.abs_diff(self.target.0) + (y-1).abs_diff(self.target.1) + 7*(current.tool.abs_diff(1)) });
|
||||
}
|
||||
if self.get_type_score((x, y+1)) != current.tool {
|
||||
res.push(NavigationState { coordinates: (x, y+1), tool: current.tool, time_elapsed: current.time_elapsed+1, projected_total: current.time_elapsed+1 + x.abs_diff(self.target.0) + (y+1).abs_diff(self.target.1) + 7*(current.tool.abs_diff(1)) });
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct NavigationState {
|
||||
coordinates: (usize, usize),
|
||||
// the tool number equals the type score of the terrain where they aren't allowed, so we can
|
||||
// reuse that for determining the allowed tools
|
||||
tool: usize,
|
||||
time_elapsed: usize,
|
||||
// projected_total is the time it took to get here + the manhattan distance between current and target + 7 if the current tool
|
||||
// is not 1 (Torch). This is guaranteed to be lower than or equal to the actual time, since we
|
||||
// will never find a faster way here by visiting later and the other summands are the actual
|
||||
// time remaining in the best case scenario.
|
||||
projected_total: usize,
|
||||
}
|
||||
|
||||
impl Ord for NavigationState {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
other.projected_total.cmp(&self.projected_total).then_with(|| other.coordinates.0.cmp(&self.coordinates.0)).then_with(|| other.coordinates.1.cmp(&self.coordinates.1)).then_with(|| other.tool.cmp(&self.tool))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for NavigationState {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(input: &str) -> (usize, usize) {
|
||||
let lines: Vec<_> = input.lines().collect();
|
||||
let depth = lines[0].split_whitespace().nth(1).unwrap().parse().unwrap();
|
||||
let target_components: Vec<_> = lines[1].split_whitespace().nth(1).unwrap().split(',').collect();
|
||||
let target = (target_components[0].parse().unwrap(), target_components[1].parse().unwrap());
|
||||
let mut regions = Regions {
|
||||
target,
|
||||
depth,
|
||||
erosion_levels: HashMap::new(),
|
||||
};
|
||||
let first = (0..=target.0).map(|x| (0..=target.1).map(|y| regions.get_type_score((x, y))).sum::<usize>()).sum();
|
||||
let second = shortest_path(&mut regions);
|
||||
(first, second)
|
||||
}
|
||||
|
||||
|
||||
fn shortest_path(regions: &mut Regions) -> usize {
|
||||
let starting = NavigationState {
|
||||
coordinates: (0, 0),
|
||||
tool: 1,
|
||||
time_elapsed: 0,
|
||||
projected_total: regions.target.0 + regions.target.1,
|
||||
};
|
||||
let mut visited = HashSet::new();
|
||||
let mut open = BTreeSet::from([starting]);
|
||||
loop {
|
||||
let current = open.pop_last().unwrap();
|
||||
if current.coordinates == regions.target && current.tool == 1 {
|
||||
return current.time_elapsed;
|
||||
}
|
||||
if visited.contains(&(current.coordinates, current.tool)) {
|
||||
continue;
|
||||
}
|
||||
visited.insert((current.coordinates, current.tool));
|
||||
regions.get_neighbours(current).into_iter().for_each(|neighbour| {
|
||||
open.insert(neighbour);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[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), (114, 45));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_challenge() {
|
||||
let challenge_input = read_file("tests/challenge_input");
|
||||
assert_eq!(run(&challenge_input), (11810, 1015));
|
||||
}
|
||||
}
|
2
2018/day22_mode_maze/tests/challenge_input
Normal file
2
2018/day22_mode_maze/tests/challenge_input
Normal file
|
@ -0,0 +1,2 @@
|
|||
depth: 3558
|
||||
target: 15,740
|
2
2018/day22_mode_maze/tests/sample_input
Normal file
2
2018/day22_mode_maze/tests/sample_input
Normal file
|
@ -0,0 +1,2 @@
|
|||
depth: 510
|
||||
target: 10,10
|
Loading…
Add table
Add a link
Reference in a new issue