This commit is contained in:
Hugo Mårdbrink 2024-12-08 18:11:19 +01:00
parent 9980433c26
commit 253a5292d9
2 changed files with 214 additions and 14 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9) cmake_minimum_required(VERSION 3.20.0)
project(aoc24 LANGUAGES CXX) project(aoc24 LANGUAGES CXX)
@ -12,7 +12,7 @@ set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 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() 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) 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() endforeach()
endif() endif()
set(CMAKE_CXX_CLANG_TIDY
clang-tidy;
-checks=*;
-header-filter=.*;
)

View file

@ -1,15 +1,220 @@
#include <iostream> #include <iostream>
#include <fstream> #include <sstream>
#include <string>
#include <vector>
#include <chrono>
#include <algorithm>
#include <ranges>
#include <unordered_set>
using std::cout, std::endl; using std::cout, std::endl;
int main() { constexpr const char content[] = {
std::ifstream file{"../d6/input.txt"}; #embed "input.txt"
std::string line; };
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<State> {
std::size_t operator()(const State& s) const {
return std::hash<int>{}(s.x) ^ std::hash<int>{}(s.y) ^ std::hash<int>{}(s.direction);
}
};
}
bool position_in_bounds(const std::vector<std::string>& 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<std::string> 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<Direction>((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<std::string>& path_map, State start_state) {
std::unordered_set<State> 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<Direction>((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<std::string> path_map;
std::unordered_set<State> 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<Direction>((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<std::chrono::microseconds>(middle - begin).count() << "µs)" << endl;
cout << "Part 2: " << p2_val << " (" << std::chrono::duration_cast<std::chrono::microseconds>(end - middle).count() << "µs)" << endl;
return 0; return 0;
} }