From 253a5292d9f7860f763be48ef889a6dece04204d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20M=C3=A5rdbrink?= Date: Sun, 8 Dec 2024 18:11:19 +0100 Subject: [PATCH] Day 6 --- CMakeLists.txt | 9 +- d06/main.cxx | 219 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 214 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e574236..3c78940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.20.0) project(aoc24 LANGUAGES CXX) @@ -12,7 +12,7 @@ set(CMAKE_CXX_COMPILER clang++) set(CMAKE_BUILD_TYPE Release) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -Wno-c23-extensions") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -Wno-c23-extensions -std=c++23}") endif() set(executables d01 d02 d03 d04 d05 d06 d07 d08 d09 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25) @@ -30,8 +30,3 @@ if(OpenMP_CXX_FOUND) endforeach() endif() -set(CMAKE_CXX_CLANG_TIDY - clang-tidy; - -checks=*; - -header-filter=.*; -) diff --git a/d06/main.cxx b/d06/main.cxx index 0470627..c2042ae 100644 --- a/d06/main.cxx +++ b/d06/main.cxx @@ -1,15 +1,220 @@ #include -#include +#include +#include +#include +#include +#include +#include +#include using std::cout, std::endl; -int main() { - std::ifstream file{"../d6/input.txt"}; - std::string line; +constexpr const char content[] = { + #embed "input.txt" +}; - while (std::getline(file, line)) { - +enum Direction { + UP, + RIGHT, + DOWN, + LEFT +}; + +struct State { + int x; + int y; + Direction direction; + + bool operator==(const State& other) const { + return x == other.x && y == other.y && direction == other.direction; } - +}; + +namespace std { + template <> + struct hash { + std::size_t operator()(const State& s) const { + return std::hash{}(s.x) ^ std::hash{}(s.y) ^ std::hash{}(s.direction); + } + }; +} + +bool position_in_bounds(const std::vector& path_map, int x, int y) { + return x >= 0 && y >= 0 && x < path_map.size() && y < path_map[0].size(); +} + +int part_1() { + std::istringstream input_stream(content); + std::string line; + std::vector path_map; + + int row{0}; + State state; + while (std::getline(input_stream, line)) { + if(line.empty()) { + continue; + } + path_map.emplace_back(line); + if(line.find('^') != std::string::npos) { + state.x = row; + state.y = line.find('^'); + state.direction = UP; + } + row++; + } + + auto unique_acc{0}; + while (position_in_bounds(path_map, state.x, state.y)) { + int walk_x{state.x}; + int walk_y{state.y}; + + switch(state.direction) { + case UP: + walk_x--; + break; + case RIGHT: + walk_y++; + break; + case DOWN: + walk_x++; + break; + case LEFT: + walk_y--; + break; + default: + break; + } + + if(!position_in_bounds(path_map, walk_x, walk_y)) { + break; + } else if(path_map[walk_x][walk_y] == '#') { + state.direction = static_cast((state.direction + 1) % 4); + } else { + state.x = walk_x; + state.y = walk_y; + + if(path_map[state.x][state.y] != 'X') { + unique_acc++; + path_map[state.x][state.y] = 'X'; + } + } + } + return unique_acc; +} + +bool loop_detected(std::vector& path_map, State start_state) { + std::unordered_set visited_states; + + State state = start_state; + while(position_in_bounds(path_map, state.x, state.y)) { + int walk_x{state.x}; + int walk_y{state.y}; + + switch(state.direction) { + case UP: + walk_x--; + break; + case RIGHT: + walk_y++; + break; + case DOWN: + walk_x++; + break; + case LEFT: + walk_y--; + break; + default: + break; + } + + if(!position_in_bounds(path_map, walk_x, walk_y)) { + return false; + } else if(path_map[walk_x][walk_y] == '#') { + state.direction = static_cast((state.direction + 1) % 4); + } else { + state.x = walk_x; + state.y = walk_y; + if(visited_states.find(state) != visited_states.end()) { + return true; + } else { + visited_states.insert(state); + } + } + } + + return false; +} + + +int part_2() { + std::istringstream input_stream(content); + std::string line; + std::vector path_map; + std::unordered_set obstacles; + + int row{0}; + State state; + while (std::getline(input_stream, line)) { + if(line.empty()) continue; + + path_map.emplace_back(line); + if(line.find('^') != std::string::npos) { + state.x = row; + state.y = line.find('^'); + state.direction = UP; + } + row++; + } + State start_state = state; + while (position_in_bounds(path_map, state.x, state.y)) { + int walk_x{state.x}; + int walk_y{state.y}; + + switch(state.direction) { + case UP: + walk_x--; + break; + case RIGHT: + walk_y++; + break; + case DOWN: + walk_x++; + break; + case LEFT: + walk_y--; + break; + default: + break; + } + + if(!position_in_bounds(path_map, walk_x, walk_y)) { + break; + } else if(path_map[walk_x][walk_y] == '#') { + state.direction = static_cast((state.direction + 1) % 4); + } else { + if(!(start_state.x == walk_x && walk_y == start_state.y)) { + path_map[walk_x][walk_y] = '#'; + if(loop_detected(path_map, start_state) && obstacles.find({walk_x, walk_y}) == obstacles.end()) { + obstacles.insert({walk_x, walk_y}); + } + path_map[walk_x][walk_y] = '.'; + } + state.x = walk_x; + state.y = walk_y; + } + + } + + return obstacles.size(); +} + +int main() { + std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); + auto p1_val = part_1(); + std::chrono::steady_clock::time_point middle = std::chrono::steady_clock::now(); + auto p2_val = part_2(); + std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + cout << "Part 1: " << p1_val << " (" << std::chrono::duration_cast(middle - begin).count() << "µs)" << endl; + cout << "Part 2: " << p2_val << " (" << std::chrono::duration_cast(end - middle).count() << "µs)" << endl; return 0; }