Added Solution for 2023 day 16

This commit is contained in:
Burnus 2023-12-16 11:59:32 +01:00
parent 6506b18dc1
commit 4d805568e2
5 changed files with 454 additions and 0 deletions

View file

@ -0,0 +1,15 @@
[package]
name = "day16_the_floor_will_be_lava"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dev-dependencies]
criterion = "0.5.1"
[[bench]]
name = "test_benchmark"
harness = false

View file

@ -0,0 +1,119 @@
With the beam of light completely focused *somewhere*, the reindeer leads you deeper still into the Lava Production Facility. At some point, you realize that the steel facility walls have been replaced with cave, and the doorways are just cave, and the floor is cave, and you're pretty sure this is actually just a giant cave.
Finally, as you approach what must be the heart of the mountain, you see a bright light in a cavern up ahead. There, you discover that the beam of light you so carefully focused is emerging from the cavern wall closest to the facility and pouring all of its energy into a contraption on the opposite side.
Upon closer inspection, the contraption appears to be a flat, two-dimensional square grid containing *empty space* (`.`), *mirrors* (`/` and `\`), and *splitters* (`|` and `-`).
The contraption is aligned so that most of the beam bounces around the grid, but each tile on the grid converts some of the beam's light into *heat* to melt the rock in the cavern.
You note the layout of the contraption (your puzzle input). For example:
```
.|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....
```
The beam enters in the top-left corner from the left and heading to the *right*. Then, its behavior depends on what it encounters as it moves:
* If the beam encounters *empty space* (`.`), it continues in the same direction.
* If the beam encounters a *mirror* (`/` or `\`), the beam is *reflected* 90 degrees depending on the angle of the mirror. For instance, a rightward-moving beam that encounters a `/` mirror would continue *upward* in the mirror's column, while a rightward-moving beam that encounters a `\` mirror would continue *downward* from the mirror's column.
* If the beam encounters the *pointy end of a splitter* (`|` or `-`), the beam passes through the splitter as if the splitter were *empty space*. For instance, a rightward-moving beam that encounters a `-` splitter would continue in the same direction.
* If the beam encounters the *flat side of a splitter* (`|` or `-`), the beam is *split into two beams* going in each of the two directions the splitter's pointy ends are pointing. For instance, a rightward-moving beam that encounters a `|` splitter would split into two beams: one that continues *upward* from the splitter's column and one that continues *downward* from the splitter's column.
Beams do not interact with other beams; a tile can have many beams passing through it at the same time. A tile is *energized* if that tile has at least one beam pass through it, reflect in it, or split in it.
In the above example, here is how the beam of light bounces around the contraption:
```
>|<<<\....
|v-.\^....
.v...|->>>
.v...v^.|.
.v...v^...
.v...v^..\
.v../2\\..
<->-/vv|..
.|<<<2-|.\
.v//.|.v..
```
Beams are only shown on empty tiles; arrows indicate the direction of the beams. If a tile contains beams moving in multiple directions, the number of distinct directions is shown instead. Here is the same diagram but instead only showing whether a tile is *energized* (`#`) or not (`.`):
```
######....
.#...#....
.#...#####
.#...##...
.#...##...
.#...##...
.#..####..
########..
.#######..
.#...#.#..
```
Ultimately, in this example, `*46*` tiles become *energized*.
The light isn't energizing enough tiles to produce lava; to debug the contraption, you need to start by analyzing the current situation. With the beam starting in the top-left heading right, *how many tiles end up being energized?*
Your puzzle answer was `8098`.
\--- Part Two ---
----------
As you try to work out what might be wrong, the reindeer tugs on your shirt and leads you to a nearby control panel. There, a collection of buttons lets you align the contraption so that the beam enters from *any edge tile* and heading away from that edge. (You can choose either of two directions for the beam if it starts on a corner; for instance, if the beam starts in the bottom-right corner, it can start heading either left or upward.)
So, the beam could start on any tile in the top row (heading downward), any tile in the bottom row (heading upward), any tile in the leftmost column (heading right), or any tile in the rightmost column (heading left). To produce lava, you need to find the configuration that *energizes as many tiles as possible*.
In the above example, this can be achieved by starting the beam in the fourth tile from the left in the top row:
```
.|<2<\....
|v-v\^....
.v.v.|->>>
.v.v.v^.|.
.v.v.v^...
.v.v.v^..\
.v.v/2\\..
<-2-/vv|..
.|<<<2-|.\
.v//.|.v..
```
Using this configuration, `*51*` tiles are energized:
```
.#####....
.#.#.#....
.#.#.#####
.#.#.##...
.#.#.##...
.#.#.##...
.#.#####..
########..
.#######..
.#...#.#..
```
Find the initial beam configuration that energizes the largest number of tiles; *how many tiles are energized in that configuration?*
Your puzzle answer was `8335`.
Both parts of this puzzle are complete! They provide two gold stars: \*\*
At this point, you should [return to your Advent calendar](/2023) and try another puzzle.
If you still want to see it, you can [get your puzzle input](16/input).

View file

@ -0,0 +1,200 @@
use core::fmt::Display;
use std::collections::{HashMap, BTreeSet};
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
EmptyInput,
InvalidChar(char),
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::EmptyInput => write!(f, "The specified input was empty"),
Self::InvalidChar(c) => write!(f, "Unable to parse {c} into a tile"),
}
}
}
#[repr(u8)]
#[derive(PartialEq)]
enum Direction {
North = 0b0001,
West = 0b0010,
East = 0b0100,
South = 0b1000,
}
impl Direction {
fn as_u8(&self) -> u8 {
match self {
Self::North => 0b0001,
Self::West => 0b0010,
Self::East => 0b0100,
Self::South => 0b1000,
}
}
fn from_u8(n: u8) -> Vec<Self> {
let mut res = Vec::new();
if n & 0b0001 > 0 {
res.push(Self::North);
}
if n & 0b0010 > 0 {
res.push(Self::West);
}
if n & 0b0100 > 0 {
res.push(Self::East);
}
if n & 0b1000 > 0 {
res.push(Self::South);
}
res
}
fn next_from(&self, x: usize, y: usize) -> Option<(usize, usize)> {
match self {
Direction::North if y > 0 => Some((x, y-1)),
Direction::North => None,
Direction::West if x > 0 => Some((x-1, y)),
Direction::West => None,
Direction::East => Some((x+1, y)),
Direction::South => Some((x, y+1)),
}
}
}
#[derive(PartialEq)]
enum Tile {
Empty, // .
SplitterNS, // |
SplitterWE, // -
MirrorNWSE, // \
MirrorNESW, // /
}
impl TryFrom<char> for Tile {
type Error = ParseError;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'.' => Ok(Self::Empty),
'|' => Ok(Self::SplitterNS),
'-' => Ok(Self::SplitterWE),
'\\' => Ok(Self::MirrorNWSE),
'/' => Ok(Self::MirrorNESW),
e => Err(Self::Error::InvalidChar(e)),
}
}
}
struct Grid {
devices: HashMap<(usize, usize), Tile>,
max: (usize, usize),
}
impl TryFrom<&str> for Grid {
type Error = ParseError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.is_empty() {
return Err(Self::Error::EmptyInput);
}
let mut max = (0, value.lines().count()-1);
let mut devices = HashMap::new();
for (y, line) in value.lines().enumerate() {
max.0 = max.0.max(line.len()-1);
for (x, c) in line.chars().enumerate() {
let tile = Tile::try_from(c)?;
if tile != Tile::Empty {
devices.insert((x, y), tile);
}
}
}
Ok(Self { devices, max, })
}
}
impl Grid {
fn get_energized(&self, starting_tile: (usize, usize), starting_direction: Direction) -> usize {
let mut energized: HashMap<(usize, usize), u8> = HashMap::from([(starting_tile, starting_direction.as_u8())]);
let mut open_set = BTreeSet::from([starting_tile]);
while let Some((x, y)) = open_set.pop_last() {
let incoming_directions = Direction::from_u8(*energized.get(&(x, y)).unwrap());
let mut directions = Vec::new();
for prev in incoming_directions {
match self.devices.get(&(x, y)) {
None => directions.push(prev),
Some(Tile::SplitterNS) if [Direction::North, Direction::South].contains(&prev) => directions.push(prev),
Some(Tile::SplitterNS) => {
directions.push(Direction::North);
directions.push(Direction::South);
},
Some(Tile::SplitterWE) if [Direction::West, Direction::East].contains(&prev) => directions.push(prev),
Some(Tile::SplitterWE) => {
directions.push(Direction::West);
directions.push(Direction::East);
},
Some(Tile::MirrorNWSE) if prev == Direction::North => directions.push(Direction::West),
Some(Tile::MirrorNWSE) if prev == Direction::West => directions.push(Direction::North),
Some(Tile::MirrorNWSE) if prev == Direction::East => directions.push(Direction::South),
Some(Tile::MirrorNWSE) if prev == Direction::South => directions.push(Direction::East),
Some(Tile::MirrorNESW) if prev == Direction::North => directions.push(Direction::East),
Some(Tile::MirrorNESW) if prev == Direction::West => directions.push(Direction::South),
Some(Tile::MirrorNESW) if prev == Direction::East => directions.push(Direction::North),
Some(Tile::MirrorNESW) if prev == Direction::South => directions.push(Direction::West),
_ => unreachable!(),
};
}
for direction in directions {
if let Some(neighbour) = direction.next_from(x, y) {
if neighbour.0 <= self.max.0 && neighbour.1 <= self.max.1 {
let prev = *energized.get(&neighbour).unwrap_or(&0);
let new_direction = direction.as_u8();
if prev & new_direction < new_direction {
open_set.insert(neighbour);
energized.insert(neighbour, new_direction | prev);
}
}
}
}
}
energized.len()
}
}
pub fn run(input: &str) -> Result<(usize, usize), ParseError> {
let grid = Grid::try_from(input)?;
let first = grid.get_energized((0,0), Direction::East);
let second = (0..grid.max.0).map(|x| grid.get_energized((x, 0), Direction::South)).max().unwrap_or(0).max(
(0..grid.max.0).map(|x| grid.get_energized((x, grid.max.1), Direction::North)).max().unwrap_or(0).max(
(0..grid.max.1).map(|y| grid.get_energized((0, y), Direction::East)).max().unwrap_or(0).max(
(0..grid.max.1).map(|y| grid.get_energized((grid.max.0, y), Direction::West)).max().unwrap_or(0)
)));
Ok((first, second))
}
#[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), Ok((46, 51)));
}
#[test]
fn test_challenge() {
let challenge_input = read_file("tests/challenge_input");
assert_eq!(run(&challenge_input), Ok((8098, 8335)));
}
}

View file

@ -0,0 +1,110 @@
\.......................\..........................................-..................-.../................-..
....../.......\...-......-.|...\..............\.................|............././....-........................
...............-...-........................................\......\..-.............|......-....\....-........
..\..|.|...........................-.|........................................./.|....|................|......
|../................|............................................................\........../..\..............
........\............../................/..........................\...\....|............./....-.........\\...
.................-...-...................\../........-|.................../......-...........|................
........-............/...|-............-.....\.|..............-....-../\../..................\...\././........
........................-|................................................................-........-..........
-......./.................|.....\.................\.....//............-........./..../....|...................
....-.............-........-..........-|.......|...../...\...................\.....................|..........
...|...\.........|.................|.....|....-....\.......\./........................-.../..../.....-........
....|....-.-..............\.........|.......................-.......-..............\................/.........
.....|.\...........-.................-.-........../...\............|...............|...|......./.......|...../
.....\.........................-.../..-./...\...................../......\...-.......|.\........-|............
............|.....................................-....../....\.............../-...|...\..\................./.
......-./|....../............|.........\............-../...-......./.\..\....../......|/...\..................
................................|.......|..-..../.............................../.-..................-..-/..|.
...............................-......./......................|./...............-............./....../........
..................../....................\........\...........................-............/.../..............
.|||......../.................|.................../..\............................-......./..|...|/.-.........
......-......./\....../.........|....../.......-...............|.\........-............/.../..................
.....................-.\/|................//.../.........|.|......\.-..|.........|.........\..................
.........................\/.......|.|............................|........|.............................././..
.................................|.................\../..|/.................\.................-...-........-/.
......................-...-.........../...........................\....\......-..-.......\.-....\....|........
......-......../..............\/..................\..|........-..............|...-...../......|...............
|.......|.../....|..............//.....................|..........|/......../................|................
...|.|..................../|..../.-.......-...........|.....|./....\......-......-................|...........
......\/./.|\..../|.|..|..........-....|...........|.-.|...................-.\.....|....................\.....
......../.\......................|.....|...........|.........../.......|....|...|.......-......../......\...-.
...|...-...||......-..|..-...........|.-.................|.................................-..................
..............-.\.-........|......\..........................................\./.\........../.....|...........
../\.........|...............|............|.\/.-/.................-....|...-.................-.....|..../.....
....................../......../..../-.....\........................\..-.\....|....-.........../-.............
.................................|................|.........|................../|.....|....\\............/.\..
...///./.....\.................|/.....................\...................-............|................|.....
............-...........................--........\................/.............-\................\.....-.../
...............\.........../|............................|.....................\...-...\.....................-
...\.............|.............|................\............\|...../...|.........................|...........
..................|......|..........-.-..............\.........................\..............................
....-................../.........../...|................/...............|./.|.../....\..../......./......//...
...../....../..............................|...\../..........-..........-........-..//..../...................
...............-......|......................|./........./............/..-...........|../.....-........-./....
..\.........................|...-.......\.................|..............-........\....-.............-....|...
.......|......|....../........\...........|......-........../......-..................../....................\
.......................|....-..|........./.|.-...............|..\......\.....-.......\...-/....|/.........\...
\......\..-.....................\..........................\................................../...........\...
-....-......../............................................................../.\.......|..............|....-..
........|......................|.............-....\................................./..\.......|..........-...
...-...............|........./......\...../.......|...|...............\.../...\.../......|.....-.\......\.....
............./.....|......................|.....................................\...||.................-....|.
./.....-................/........|./....-......../......./..............\..................................\..
.../..../\........-..........................|.-/.|..\................\\-.......|......./...||.......|........
.....-.........................-...............\...........|.............-.\.../.|......-.|......../...-.....-
......\....................|...../......................|.../......-..|............|......./.../.........|....
...|...........-....................................../.|............./....|..../........./.....\../..........
....../.../................\........................\...\....\......\............../|...............\.-.......
./....\.../.............|............................-.../............../............/...........\...|........
............................|.................|/..........//.........../..-...............|...................
.....\......\.................|.....|...\-./...............\................|....../.....-..\........-....-...
........................./-........\................./........-/.|....-.......\............-/\......|.\...-...
..../../..|.|...............\.......................................-.........................................
...........|...................................................-...-......|..................\............../.
/....|......................................................................|\.../.......-...........-...|....
......|.-.\......-........|.....-..|.\..............-......./......-|.........................-...............
............\......................................|........................|.-...............................
.........-.........../....\./....../.-...-..//.........../.......\\...........................................
........\......../............./...-......\.../..|..|............................../......../..\..............
--.........|.....-...|............../...|.......|..............\|............|.........................|.-....
-\......./..............-....-....\...|.-........\/.\./............-/...\........|-.........../../...\........
.\|\..............-......-.\...-....\..........................\........|...........-......./.............../.
..........................|...\..../.../..........\.............-...//...............\..................-.....
........./..........................\............|-.....|..-...|......../........-...........................\
.......\.../.....\....../.......|..|...............-......................|....-...................-.|........
......|.......\.../..............................-..............................|......-.-...................\
/.....|.......-............/|.....|-......./..../......-........../..|......../.-..\..../....../...|..........
............/..--..........-............\.......\................\........................../../....|.........
..|..-................|.|..|................/.......\............-//.......................\..\...............
.......................-......-..................|....\................-......\.|....\....|..../../|.-........
........................-..................-...........................-..-................-................|.
/.\....|.-.................................\..-.....\./.........../-.|..............\..\.....--|/....\........
.......-..-../..................\..--|..............|...............|\........|...--................|./.\.....
..........|................-.......|..................................................|...................|...
-.-..|....-.|........-./...|.-.........\.....\/........-........\........../................./.../........\...
..................../...|/......................................../............\.|./../................/\|....
...//.........................\....../..............\../.......-..\....|......................................
............................./..|./../.........-/..\..........................................................
......\.....|..................|..................\.....\.-..\...../............................../...........
..........\...........-..........-.....-....\/................../.................................\.....|..\..
..../.\...................................\............\...\....|.................|.....................-.....
...........-...........................\.......|-../.|....|.....|......................-...../................
.......|.........\..............|....\...-......../...........-.....-..-...........-..................\...\.|.
...........|.......................|....-..........\............................\.................../.\.......
..../.................\.......-..|.................../........................|...............\...........-.|.
............./..|.-\..../.....-............-....|..\......|......../............-.........|................\..
...................\...\/......\............|......................\....|...................-./-..............
..-\...........|.................../.....|....|............................-..|............\.............\....
.|.....\....\........|..................\...............|..-/.........|.-/...........-............-...........
.....\...../......-............|........./..|............-........................\....-......................
......\......../........|..............\...-..-...|.......................................................|...
...................|.................................\.....\...........................|../.|.-......-........
..................|..............\.....\............|........../....../...............\.........\.............
..|...........-..../....\.........--...\................../.............-...-....................-..../....|..
.|...\...................|......-...........-\..........\.....|.....|..........|.........|....|-../...........
.............\|...................../\...............\....../.......-....\.....................-..............
.......//.....................\....\......\......\.........|...................../......../.........\......-..
.\./.........-...-./-.\.............../......|................................\|....\...../....-..............
.......|......../......../......./.........../...............|............................../..|......../.....
............./.........|.....-./.........../....-......./|......-................|............................

View file

@ -0,0 +1,10 @@
.|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....