Skip to content

Commit 9aaba27

Browse files
day 18 (#36)
1 parent 997b2a4 commit 9aaba27

25 files changed

+6630
-42
lines changed

.github/workflows/Doxygen.yaml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Documentation
2+
3+
on:
4+
push:
5+
branches: [master ]
6+
7+
jobs:
8+
build:
9+
name: Build and publish documentation
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Install Doxygen
14+
run: sudo apt-get install doxygen
15+
- name: Generate documentation
16+
run: doxygen
17+
- name: Deploy to GitHub Pages
18+
uses: Cecilapp/GitHub-Pages-deploy@v3
19+
env:
20+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21+
with:
22+
email: ${{secrets.EMAIL}}
23+
build_dir: ./docs/html

Doxyfile

+2,726
Large diffs are not rendered by default.

day_16/lib/maze.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@ namespace aoc::day_16 {
88
/// @brief Parses the maze from the input
99
/// @param lines The input to parse
1010
/// @return The parsed maze
11-
auto parseMaze(std::vector<std::string_view> lines) -> std::vector<std::vector<maze_cell>> {
12-
std::vector<std::vector<maze_cell>> maze;
11+
auto parseMaze(std::vector<std::string_view> lines) -> std::vector<std::vector<aoc::path_finding::maze_cell>> {
12+
std::vector<std::vector<aoc::path_finding::maze_cell>> maze;
1313
for (auto const & line : lines) {
14-
std::vector<maze_cell> row;
14+
std::vector<aoc::path_finding::maze_cell> row;
1515
for (auto const & cell : line) {
1616
switch (cell) {
1717
case '#':
18-
row.push_back(maze_cell::WALL);
18+
row.push_back(aoc::path_finding::maze_cell::WALL);
1919
break;
2020
case '.':
21-
row.push_back(maze_cell::EMPTY);
21+
row.push_back(aoc::path_finding::maze_cell::EMPTY);
2222
break;
2323
case 'S':
24-
row.push_back(maze_cell::START);
24+
row.push_back(aoc::path_finding::maze_cell::START);
2525
break;
2626
case 'E':
27-
row.push_back(maze_cell::END);
27+
row.push_back(aoc::path_finding::maze_cell::END);
2828
break;
2929
default:
3030
throw std::invalid_argument("Invalid cell type in maze");

day_16/lib/maze.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
#include <string_view>
44
#include <vector>
55

6-
#include "maze_cell.hpp"
6+
#include "../../shared/src/maze_cell.hpp"
77

88
namespace aoc::day_16 {
99

1010
/// @brief Parses the maze from the input
1111
/// @param lines The input to parse
1212
/// @return The parsed maze
13-
auto parseMaze(std::vector<std::string_view> lines) -> std::vector<std::vector<maze_cell>>;
13+
auto parseMaze(std::vector<std::string_view> lines) -> std::vector<std::vector<aoc::path_finding::maze_cell>>;
1414

1515
} // namespace aoc::day_16

day_16/src/main.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
#include <unordered_set>
66
#include <vector>
77

8+
#include "../../shared/src/astar.hpp"
89
#include "../../shared/src/exit_code.hpp"
910
#include "../../shared/src/file_operations.hpp"
1011
#include "../../shared/src/grid_processor.hpp"
1112
#include "../../shared/src/print_compatibility_layer.hpp"
1213

13-
#include "../lib/astar.hpp"
1414
#include "../lib/maze.hpp"
1515

1616
auto main(int argc, char const ** argv) -> int {
@@ -29,9 +29,12 @@ auto main(int argc, char const ** argv) -> int {
2929

3030
auto maze = aoc::day_16::parseMaze(grid);
3131

32-
// Part 1
32+
auto scoringFun = [](aoc::path_finding::Node const & a, aoc::path_finding::Node const & b) {
33+
return a.direction == b.direction ? 1 : 1001;
34+
};
3335

34-
auto shortest_route = aoc::day_16::MazeSolver(maze).findPath();
36+
// Part 1
37+
auto shortest_route = aoc::path_finding::MazeSolver(maze, scoringFun).findPath();
3538

3639
if (shortest_route.cost == -1) {
3740
std::println("No path found");
@@ -41,7 +44,7 @@ auto main(int argc, char const ** argv) -> int {
4144

4245
// Part 2
4346

44-
auto shortest_routes = aoc::day_16::MazeSolver(maze).findPaths();
47+
auto shortest_routes = aoc::path_finding::MazeSolver(maze, scoringFun).findPaths();
4548

4649
std::println("Found {} paths", shortest_routes.size());
4750

day_16/test/maze_test.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <gtest/gtest.h>
44

55
using namespace aoc::day_16;
6+
using namespace aoc::path_finding;
67
using ::testing::ElementsAre;
78

89
TEST(MazeTest, ParsesEmptyMaze) {

day_18/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
aoc_day(18)

day_18/lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
aoc_add_library()

day_18/lib/blocker.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include "blocker.hpp"
2+
3+
#include <algorithm>
4+
#include <ranges>
5+
6+
namespace aoc::day_18 {
7+
8+
auto scoringFun(aoc::path_finding::Node const & a, aoc::path_finding::Node const & b) -> int {
9+
return 1;
10+
}
11+
12+
auto validatePath(maze const & maze, auto const & scoringFun) -> bool {
13+
auto shortest_route = aoc::path_finding::MazeSolver(maze.m_maze, scoringFun).findPath();
14+
return shortest_route.cost == -1;
15+
}
16+
17+
auto findCriticalWall(std::vector<std::vector<int16_t>> const & coordinates, size_t min)
18+
-> std::pair<int16_t, int16_t> {
19+
for (auto i : std::views::iota(min, coordinates.size()) | std::views::reverse) {
20+
auto test_maze = buildMaze(coordinates, i);
21+
if (!validatePath(test_maze, scoringFun)) {
22+
return {coordinates[i][0], coordinates[i][1]};
23+
}
24+
}
25+
return {-1, -1};
26+
}
27+
} // namespace aoc::day_18

day_18/lib/blocker.hpp

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <utility>
5+
#include <vector>
6+
7+
#include "maze.hpp"
8+
9+
#include "../../shared/src/astar.hpp"
10+
11+
namespace aoc::day_18 {
12+
13+
/// @brief Scoring function for A* pathfinding
14+
/// @param a First node
15+
/// @param b Second node
16+
/// @return Cost between nodes
17+
auto scoringFun(aoc::path_finding::Node const & a, aoc::path_finding::Node const & b) -> int;
18+
19+
/// @brief Validates if a path exists through the maze
20+
/// @param maze The maze to validate
21+
/// @param scoringFun Function used to score path segments
22+
/// @return True if no path exists, false otherwise
23+
auto validatePath(maze const & maze, auto const & scoringFun) -> bool;
24+
25+
/// @brief Finds the critical wall that blocks all paths
26+
/// @param coordinates Vector of coordinate pairs
27+
/// @param min Minimum index to start searching from
28+
/// @return Pair of coordinates for the critical wall, or {-1,-1} if none found
29+
auto findCriticalWall(std::vector<std::vector<int16_t>> const & coordinates, size_t min = 1025ull)
30+
-> std::pair<int16_t, int16_t>;
31+
} // namespace aoc::day_18

day_18/lib/maze.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "maze.hpp"
2+
3+
#include <ranges>
4+
#include <string>
5+
#include <vector>
6+
7+
#include "../../shared/src/maze_cell.hpp"
8+
9+
namespace aoc::day_18 {
10+
11+
#define DIMENSIONS 71
12+
13+
maze::maze() {
14+
m_maze = std::vector<std::vector<aoc::path_finding::maze_cell>>(
15+
DIMENSIONS, std::vector<aoc::path_finding::maze_cell>(DIMENSIONS, aoc::path_finding::maze_cell::EMPTY));
16+
m_maze[0][0] = aoc::path_finding::maze_cell::START;
17+
m_maze[DIMENSIONS - 1][DIMENSIONS - 1] = aoc::path_finding::maze_cell::END;
18+
}
19+
20+
std ::string maze::to_string() {
21+
std::string result;
22+
for (size_t y = 0; y < DIMENSIONS; ++y) {
23+
for (size_t x = 0; x < DIMENSIONS; ++x) {
24+
switch (m_maze[x][y]) {
25+
case aoc::path_finding::maze_cell::EMPTY:
26+
result += ".";
27+
break;
28+
case aoc::path_finding::maze_cell::WALL:
29+
result += "#";
30+
break;
31+
case aoc::path_finding::maze_cell::START:
32+
result += "S";
33+
break;
34+
case aoc::path_finding::maze_cell::END:
35+
result += "E";
36+
break;
37+
}
38+
}
39+
result += "\n";
40+
}
41+
return result;
42+
}
43+
44+
auto buildMaze(std::vector<std::vector<int16_t>> const & coordinates, size_t limit) -> maze {
45+
auto result = maze{};
46+
for (auto const & [x, y] : coordinates | std::views::take(limit) | std::views::transform([](auto const & line) {
47+
return std::pair{line[0], line[1]};
48+
})) {
49+
result.m_maze[x][y] = aoc::path_finding::maze_cell::WALL;
50+
}
51+
return result;
52+
}
53+
54+
} // namespace aoc::day_18

day_18/lib/maze.hpp

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
#include <ranges>
4+
#include <string>
5+
#include <vector>
6+
7+
#include "../../shared/src/maze_cell.hpp"
8+
9+
namespace aoc::day_18 {
10+
11+
#define DIMENSIONS 71
12+
13+
/// @brief Represents a 2D maze with start and end points
14+
struct maze {
15+
/// @brief Constructs an empty maze with start and end points
16+
maze();
17+
18+
/// @brief Converts the maze to a string representation
19+
/// @return String representation of the maze
20+
std ::string to_string();
21+
22+
/// @brief The actual maze data
23+
std::vector<std::vector<aoc::path_finding::maze_cell>> m_maze;
24+
};
25+
26+
/// @brief Builds a maze from coordinate pairs
27+
/// @param coordinates Vector of coordinate pairs
28+
/// @param limit Maximum number of coordinates to use
29+
/// @return Constructed maze
30+
auto buildMaze(std::vector<std::vector<int16_t>> const & coordinates, size_t limit) -> maze;
31+
32+
} // namespace aoc::day_18

day_18/lib/parser.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "parser.hpp"
2+
3+
#include <execution>
4+
5+
#include "../../shared/src/file_operations.hpp"
6+
#include "../../shared/src/line_splitter.hpp"
7+
#include "../../shared/src/parsing_rules.hpp"
8+
9+
namespace aoc::day_18 {
10+
11+
auto parseInput(std::string_view filename) -> std::expected<std::vector<std::vector<int16_t>>, std::error_code> {
12+
auto input = aoc::file_operations::read(filename);
13+
if (!input) {
14+
return std::unexpected(input.error());
15+
}
16+
17+
return aoc::splitter::linebased::split<int16_t, std::vector>(*input, aoc::parser::rules::parse_number<int16_t>,
18+
std::execution::seq, ',');
19+
}
20+
21+
} // namespace aoc::day_18

day_18/lib/parser.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
#include <expected>
5+
#include <string_view>
6+
#include <system_error>
7+
#include <vector>
8+
9+
namespace aoc::day_18 {
10+
11+
/// @brief Parses the input file containing coordinate pairs
12+
/// @param filename Path to the input file
13+
/// @return Vector of coordinate pairs on success, error code on failure
14+
auto parseInput(std::string_view filename) -> std::expected<std::vector<std::vector<int16_t>>, std::error_code>;
15+
16+
} // namespace aoc::day_18

day_18/src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aoc_add_executable()
2+
configure_file(input.txt input.txt COPYONLY)

0 commit comments

Comments
 (0)