diff options
| -rw-r--r-- | 2024/src/day12.cpp | 93 |
1 files changed, 69 insertions, 24 deletions
diff --git a/2024/src/day12.cpp b/2024/src/day12.cpp index 6a23730..018797f 100644 --- a/2024/src/day12.cpp +++ b/2024/src/day12.cpp | |||
| @@ -8,7 +8,9 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | using namespace std; | 9 | using namespace std; |
| 10 | 10 | ||
| 11 | using pos_type = tuple<size_t, size_t>; | 11 | using pos_type = tuple<size_t, size_t>; |
| 12 | using area_type = set<pos_type>; | ||
| 13 | using areas_type = vector<area_type>; | ||
| 12 | 14 | ||
| 13 | map<pos_type, char> | 15 | map<pos_type, char> |
| 14 | read_file(string_view filename) | 16 | read_file(string_view filename) |
| @@ -33,69 +35,112 @@ neighbors(pos_type pos) | |||
| 33 | return { { x - 1, y }, { x, y - 1 }, { x + 1, y }, { x, y + 1 } }; | 35 | return { { x - 1, y }, { x, y - 1 }, { x + 1, y }, { x, y + 1 } }; |
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | void | 38 | areas_type |
| 37 | part1(const map<pos_type, char>& data) | 39 | areas(map<pos_type, char> data) |
| 38 | { | 40 | { |
| 39 | auto data_copy = data; | 41 | auto find_area = [&](pos_type start) { |
| 40 | |||
| 41 | auto flood_fill = [&](pos_type start) { | ||
| 42 | set<pos_type> area; | 42 | set<pos_type> area; |
| 43 | queue<pos_type> queue; | 43 | queue<pos_type> queue; |
| 44 | queue.push(start); | 44 | queue.push(start); |
| 45 | 45 | ||
| 46 | const auto digit = data.at(start); | ||
| 47 | |||
| 46 | while ( !queue.empty() ) { | 48 | while ( !queue.empty() ) { |
| 47 | auto pos = queue.front(); | 49 | auto pos = queue.front(); |
| 48 | queue.pop(); | 50 | queue.pop(); |
| 49 | 51 | ||
| 50 | if ( !data_copy.contains(pos) ) { | 52 | if ( !data.contains(pos) ) { |
| 51 | continue; | 53 | continue; |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | auto digit = data_copy.at(pos); | ||
| 55 | |||
| 56 | for ( const auto& neighbor: neighbors(pos) ) { | 56 | for ( const auto& neighbor: neighbors(pos) ) { |
| 57 | if ( !data_copy.contains(neighbor) ) { | 57 | if ( !data.contains(neighbor) ) { |
| 58 | continue; | 58 | continue; |
| 59 | } | 59 | } |
| 60 | if ( data_copy.at(neighbor) != digit ) { | 60 | if ( data.at(neighbor) != digit ) { |
| 61 | continue; | 61 | continue; |
| 62 | } | 62 | } |
| 63 | queue.push(neighbor); | 63 | queue.push(neighbor); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | area.insert(pos); | 66 | area.insert(pos); |
| 67 | data_copy.erase(pos); | 67 | data.erase(pos); |
| 68 | } | 68 | } |
| 69 | return area; | 69 | return area; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | auto count_edges = [](const set<pos_type>& area) -> size_t { | 72 | areas_type areas; |
| 73 | size_t sum = 0; | 73 | while ( !data.empty() ) { |
| 74 | auto area = find_area(data.begin()->first); | ||
| 75 | areas.push_back(area); | ||
| 76 | } | ||
| 77 | return areas; | ||
| 78 | } | ||
| 74 | 79 | ||
| 75 | for ( const auto& pos: area ) { | 80 | size_t |
| 76 | for ( const auto& neighbor: neighbors(pos) ) { | 81 | count_edges(const set<pos_type>& area) |
| 77 | if ( !area.contains(neighbor) ) { | 82 | { |
| 78 | ++sum; | 83 | size_t sum = 0; |
| 79 | } | 84 | for ( const auto& pos: area ) { |
| 85 | for ( const auto& neighbor: neighbors(pos) ) { | ||
| 86 | if ( !area.contains(neighbor) ) { | ||
| 87 | ++sum; | ||
| 80 | } | 88 | } |
| 81 | } | 89 | } |
| 90 | } | ||
| 91 | return sum; | ||
| 92 | } | ||
| 82 | 93 | ||
| 83 | return sum; | 94 | size_t |
| 84 | }; | 95 | count_common_sides(const set<pos_type>& area) |
| 96 | { | ||
| 97 | size_t count = 0; | ||
| 98 | for ( const auto& [x, y]: area ) { | ||
| 99 | if ( area.contains({ x - 1, y }) ) { | ||
| 100 | for ( const auto y2: { y - 1, y + 1 } ) { | ||
| 101 | if ( !area.contains({ x, y2 }) && !area.contains({ x - 1, y2 }) ) { | ||
| 102 | ++count; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | if ( area.contains({ x, y - 1 }) ) { | ||
| 107 | for ( const auto x2: { x - 1, x + 1 } ) { | ||
| 108 | if ( !area.contains({ x2, y }) && !area.contains({ x2, y - 1 }) ) { | ||
| 109 | ++count; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | return count; | ||
| 115 | } | ||
| 85 | 116 | ||
| 117 | void | ||
| 118 | part1(const map<pos_type, char>& data) | ||
| 119 | { | ||
| 86 | size_t sum = 0; | 120 | size_t sum = 0; |
| 87 | while ( !data_copy.empty() ) { | 121 | for ( const auto& area: areas(data) ) { |
| 88 | auto area = flood_fill(data_copy.begin()->first); | ||
| 89 | auto edges = count_edges(area); | 122 | auto edges = count_edges(area); |
| 90 | |||
| 91 | sum += area.size() * edges; | 123 | sum += area.size() * edges; |
| 92 | } | 124 | } |
| 93 | cout << sum << endl; | 125 | cout << sum << endl; |
| 94 | } | 126 | } |
| 95 | 127 | ||
| 128 | void | ||
| 129 | part2(const map<pos_type, char>& data) | ||
| 130 | { | ||
| 131 | size_t sum = 0; | ||
| 132 | for ( const auto& area: areas(data) ) { | ||
| 133 | auto edges = count_edges(area); | ||
| 134 | auto common_sides = count_common_sides(area); | ||
| 135 | sum += area.size() * (edges - common_sides); | ||
| 136 | } | ||
| 137 | cout << sum << endl; | ||
| 138 | } | ||
| 139 | |||
| 96 | int | 140 | int |
| 97 | main() | 141 | main() |
| 98 | { | 142 | { |
| 99 | auto data = read_file("data/day12.txt"); | 143 | auto data = read_file("data/day12.txt"); |
| 100 | part1(data); | 144 | part1(data); |
| 145 | part2(data); | ||
| 101 | } | 146 | } |
