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)
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()
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 <fstream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <ranges>
using std::cout, std::endl;
int main() {
std::ifstream file{"../d12/input.txt"};
std::string line;
constexpr const char content[] = {
#embed "input.txt"
};
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;
}