I made some eggnog a few weeks ago, and just tried a sample of it today after letting it age. Whew. It's strong. Hopefully I don't get food poisoning or something, because I made like a gallon...
This one doesn't seem too bad at first glance. The naïve solution that comes to mind is to put each into an array (maybe a 3d bool array?). Iterate over the array, and count up the number of adjacent true
values in each cardinal direction. Add 6-count
to a total. It looks like in my input there's nothing larger than maybe 18, so to be safe it'll be a 20^3 (8000) bool array. Small enough to just iterate over quickly.
vector<vector<vector<bool>>> drop;
uint64_t surfaceArea = 0;
for (int x = 0; x < DROP_SIZE; x++)
for (int y = 0; y < DROP_SIZE; y++)
for (int z = 0; z < DROP_SIZE; z++)
{
if (!drop[x][y][z]) continue;
surfaceArea += 6;
if (x+1 < DROP_SIZE && drop[x+1][y][z]) surfaceArea--;
if (x > 0 && drop[x-1][y][z]) surfaceArea--;
if (y+1 < DROP_SIZE && drop[x][y+1][z]) surfaceArea--;
if (y > 0 && drop[x][y-1][z]) surfaceArea--;
if (z+1 < DROP_SIZE && drop[x][y][z+1]) surfaceArea--;
if (z > 0 && drop[x][y][z-1]) surfaceArea--;
}
That was... desceptively easy for a part one this late.
Yep, that makes sense. The real problem is the air pockets. This one doesn't seem so bad though, I think I remember solving a similar problem in a job interview ages ago, where I had to figure out how may 'blobs' were in a 2d array. This is functionally the same.
I'm making the assumption 0,0,0
is going to be the 'outside' air, so:
- Cache every empty space that is that, or adjacent to an 'outside' space. Simple breadth first search.
- Go through array again, and 'fill' every 'empty' space that is not in the outside space
- Calculate surface area
I don't even have to change any of my original code, just add an extra processing pass.
#define COORD tuple<int, int, int>
set<COORD> outside;
queue<COORD> outCheck;
// Cache 'outside' spaces
outCheck.push(COORD(0, 0, 0));
while (!outCheck.empty())
{
auto c = outCheck.front(); outCheck.pop();
if (!outside.insert(c).second) continue;
int x = get<0>(c), y = get<1>(c), z = get<2>(c);
if (x+1 < DROP_SIZE && !drop[x+1][y][z]) outCheck.push(COORD(x+1, y, z));
if (x > 0 && !drop[x-1][y][z]) outCheck.push(COORD(x-1, y, z));
if (y+1 < DROP_SIZE && !drop[x][y+1][z]) outCheck.push(COORD(x, y+1, z));
if (y > 0 && !drop[x][y-1][z]) outCheck.push(COORD(x, y-1, z));
if (z+1 < DROP_SIZE && !drop[x][y][z+1]) outCheck.push(COORD(x, y, z+1));
if (z > 0 && !drop[x][y][z-1]) outCheck.push(COORD(x, y, z-1));
}
// Fill in air pockets
for (int x = 0; x < DROP_SIZE; x++)
for (int y = 0; y < DROP_SIZE; y++)
for (int z = 0; z < DROP_SIZE; z++)
{
if (drop[x][y][z]) continue;
if (outside.find(COORD(x, y, z)) != outside.end()) continue;
drop[x][y][z] = true;
}
And that really was it. Huh. That was easy, and kind a fun.
Also look, somebody 3d printed their input!