Day 12
This commit is contained in:
parent
4f330f79a6
commit
d1fb679ef0
2 changed files with 203 additions and 7 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
208
d12/main.cxx
208
d12/main.cxx
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue