This commit is contained in:
Hugo Mårdbrink 2024-12-13 13:32:38 +01:00
parent 4f330f79a6
commit d1fb679ef0
2 changed files with 203 additions and 7 deletions

View file

@ -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 -std=c++23}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -Wno-c23-extensions -std=c++23 -g")
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)

View file

@ -1,15 +1,211 @@
#include <string>
#include <sstream>
#include <chrono>
#include <iostream> #include <iostream>
#include <fstream> #include <vector>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <ranges>
using std::cout, std::endl; using std::cout, std::endl;
int main() { constexpr const char content[] = {
std::ifstream file{"../d12/input.txt"}; #embed "input.txt"
std::string line; };
while (std::getline(file, line)) { struct Position {
int x;
int y;
bool operator==(const Position& other) const {
return x == other.x && y == other.y;
}
};
struct SidePosition {
int x;
int y;
bool operator==(const Position& other) const {
return x == other.x && y == other.y;
}
};
struct Region {
char type;
std::vector<Position> positions;
int perimeter;
};
struct SideRegion {
char type;
std::vector<SidePosition> positions;
int corners;
};
namespace std {
template <>
struct hash<std::pair<int, int>> {
size_t operator()(const std::pair<int, int>& p) const {
return std::hash<int>{}(p.first) ^ std::hash<int>{}(p.second);
}
};
} }
void find_region(std::vector<std::string>& garden, std::vector<Region>& regions, std::unordered_set<std::pair<int, int>>& visited, Position p, Region& curr_region, char target) {
if(p.x < 0 || p.x >= garden.size() || p.y < 0 || p.y >= garden[p.x].size()) {
return;
}
for(auto [i, j] : {std::pair{0, 1}, {0, -1}, {1, 0}, {-1, 0}}) {
if(p.x + i >= 0 && p.x + i < garden.size() && p.y + j >= 0 && p.y + j < garden[p.x].size()) {
if(garden[p.x + i][p.y + j] == target && !visited.contains({p.x + i, p.y + j})) {
visited.insert({p.x + i, p.y + j});
find_region(garden, regions, visited, {p.x + i, p.y + j}, curr_region, target);
} else if(garden[p.x + i][p.y + j] != target){
curr_region.perimeter++;
}
} else {
curr_region.perimeter++;
}
}
curr_region.positions.push_back(p);
}
int part_1() {
std::istringstream input_stream(content);
std::string line;
std::vector<std::string> garden = {};
std::vector<Region> regions = {};
std::unordered_set<std::pair<int,int>> visited = {};
while(getline(input_stream, line)) {
garden.emplace_back(line);
}
int id = 0;
for(int x = 0; x < garden.size(); x++) {
for(int y = 0; y < garden[x].size(); y++) {
if(!visited.contains({x, y})) {
auto curr_region = Region{garden[x][y], {}, 0};
visited.insert({x, y});
find_region(garden, regions, visited, {x, y}, curr_region, garden[x][y]);
regions.push_back(curr_region);
}
}
}
int total = 0;
for(auto& region : regions) {
total += region.perimeter * region.positions.size();
}
return total;
}
void find_corners(std::vector<std::string>& garden, std::vector<SideRegion>& regions, std::unordered_set<std::pair<int, int>>& visited, SidePosition p, SideRegion& curr_region, char target) {
if(p.x < 0 || p.x >= garden.size() || p.y < 0 || p.y >= garden[p.x].size()) {
return;
}
int edge_count = 0;
for(auto [i, j] : {std::pair{0, 1}, {0, -1}, {1, 0}, {-1, 0}}) {
if(p.x + i >= 0 && p.x + i < garden.size() && p.y + j >= 0 && p.y + j < garden[p.x].size()) {
if(garden[p.x + i][p.y + j] != target) {
edge_count++;
}
} else {
edge_count++;
}
}
if(edge_count == 0) {
for(auto [i, j] : {std::pair{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}) {
if(p.x + i >= 0 && p.x + i < garden.size() && p.y + j >= 0 && p.y + j < garden[p.x].size()) {
if(garden[p.x + i][p.y + j] != target) {
edge_count++;
}
} else {
edge_count++;
}
}
if(edge_count == 1) {
curr_region.corners++;
}
} else if(edge_count == 2) {
curr_region.corners++;
}
for(auto [i, j] : {std::pair{0, 1}, {0, -1}, {1, 0}, {-1, 0}}) {
if(p.x + i >= 0 && p.x + i < garden.size() && p.y + j >= 0 && p.y + j < garden[p.x].size()) {
if(garden[p.x + i][p.y + j] == target && !visited.contains({p.x + i, p.y + j})) {
visited.insert({p.x + i, p.y + j});
find_corners(garden, regions, visited, {p.x + i, p.y + j}, curr_region, target);
} else if(garden[p.x + i][p.y + j] != target){
}
} else {
}
}
curr_region.positions.push_back(p);
}
int part_2() {
std::istringstream input_stream(content);
std::string line;
std::vector<std::string> garden = {}, scaled_garden = {};
std::vector<SideRegion> regions = {};
std::unordered_set<std::pair<int,int>> visited = {};
while(getline(input_stream, line)) {
garden.emplace_back(line);
}
for(auto& row : garden) {
std::string s{""};
for(int i = 0; i < row.size(); i++) {
for(auto _ : std::views::iota(0, 3)) {
s.push_back(row[i]);
}
}
for(auto _ : std::views::iota(0, 3)) {
scaled_garden.push_back(s);
}
}
int id = 0;
for(int x = 0; x < scaled_garden.size(); x++) {
for(int y = 0; y < scaled_garden[x].size(); y++) {
if(!visited.contains({x, y})) {
auto curr_region = SideRegion{scaled_garden[x][y], {}, 0};
visited.insert({x, y});
find_corners(scaled_garden, regions, visited, {x, y}, curr_region, scaled_garden[x][y]);
regions.push_back(curr_region);
}
}
}
int total = 0;
for(auto& region : regions) {
total += region.corners * (region.positions.size()/9) ;
}
return total;
}
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;
} }