-
Notifications
You must be signed in to change notification settings - Fork 0
/
day18.cpp
93 lines (83 loc) · 2.47 KB
/
day18.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <chrono>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
using Holes = std::set<std::pair<int, int>>;
Holes setup(int part)
{
Holes holes;
int x = 0, y = 0;
std::ifstream f("18-input.txt");
std::string line;
char dir;
int len;
std::string color_str;
const char dirs[] = {'R', 'D', 'L', 'U'};
if (f.is_open())
{
while (std::getline(f, line))
{
std::istringstream line_stream(line);
line_stream >> dir >> len >> color_str;
if (part == 2) {
len = std::stoi(color_str.substr(2, color_str.size() - 4), nullptr, 16);
dir = dirs[color_str[color_str.size() - 2] - '0'];
}
// Dig the edge holes
for (int i = 0; i < len; i++) {
switch(dir) {
case 'R': x++; break;
case 'L': x--; break;
case 'U': y++; break;
case 'D': y--; break;
}
holes.insert({y, x});
}
}
}
f.close();
return holes;
}
void solve(int part, const Holes& holes) {
// Scanline-based area algorithm, developed from scratch.
// ~1 min for part 2. Definitely could be optimized or replaced with a more
// efficient algorithm (i.e. shoelace/pick).
unsigned long ans = 0;
int prev_y = -1;
int prev_x = -1;
bool inside = false, above = false, below = false;
for (auto [y, x] : holes) {
ans++; // Count this hole
if (y != prev_y) { // Starting a new row?
inside = false; // Always start on the outside
above = holes.count({y + 1, x}) > 0; // Is there a hole above?
below = holes.count({y - 1, x}) > 0; // Is there a hole below?
} else { // Continuing a row
if (holes.count({y + 1, x}) > 0) { above = !above; }
if (holes.count({y - 1, x}) > 0) { below = !below; }
if (inside) { ans += x - prev_x - 1; } // Count interior spaces
}
// Toggle inside if we've seen a wall both above and below
if (above && below) {
above = below = false;
inside = !inside;
}
prev_x = x;
prev_y = y;
}
std::cout << "Part " << part << ": " << ans << std::endl;
}
int main()
{
auto start = std::chrono::high_resolution_clock::now();
const Holes& holes1 = setup(1);
solve(1, holes1);
const Holes& holes2 = setup(2);
solve(2, holes2);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Clock time: " << duration.count() << " us" << std::endl;
return 0;
}