--- Day 15: Cave searching ---

December 15

Listening to: PS1 Jungle Mix


This one doesn't seem too difficult. Figure out which spaces aren't being covered by a radius given. The input is a pretty roundabout way of doing it, but it's pretty simple that you're given a center point (the Sensor), and a radius (the distance between the Beacon and the Sensor). From there, find the number of points covered by a circle.

... at least I assumed it would be that. But it's asking for row y=2000000. That's 4*10^12 spaces, not something that can easily be taken care of.... hmmm....

Oh! Something simpler. Of course. This is just building up to it. The first part is just for a single row, and the next part is for every row. I just need to figure out overlapping line segments. It'll be a bit fiddly figuring out a few of the details, but it would essentially be a line segment centered on the Sensor's x position, and the width the distance between it and the beacon, minus the number of rows away it is from the current row.

Below for example, for the beacon on row 7 with a radius 6, on row 10, the width would be 1 + 2(r-h) = 7

               1    1    2    2
     0    5    0    5    0    5
 6 ............................
 7 ..........S.................
 8 ..........|.................
 9 ..........|.................
10 .......xxxxxxx..............
11 ............................

Because of this, essentially, what I need to keep track of for each row is a list of line segments.

vector<pair<int, int>> segments;
for (Circle b: beacons)
{
    int offset = b.r - (b.y - CHECK_ROW);
    if (offset < 0) continue;

    segments.push_back(pair<int, int>(b.x-offset, b.x+offset));
}

And because they inevitably overlap, merge them a bit!

// Merge line segments
int i = 0;
while (i < segments.size()-1)
{
    // If this and next overlap
    if (segments[i].second >= segments[i+1].first)
    {
        // use max to handle case where next segment fully within first segment
        segments[i].second = max(segments[i].second, segments[i+1].second);
        segments.erase(segments.begin()+i+1);
    }
    else i++;
}

Okay, interesting... now we're getting to finding the space that isn't covered. Kind of what I was first expecting, considering the wording of the problem. But the good news is that, if my assumption is correct, only one row will have an empty spot. If I just look for segments of size 2 (instead of 1) that should be the row, and the missing space from that should be the answer! Just need to iterate over all of the rows instead of just the one.

One thing to keep in mind is that it's constrained between 0 and 4000000, so I'll need to adjust the initial line segments to keep that in mind too.

int smin = max(b.x-offset, 0);
int smax = min(b.x+offset, RANGE_MAX);

segments.push_back(pair<int, int>(smin, smax));

... okay that's a large number. Word of advice for anyone else trying: use a int64_t instead of an int. These are large numbers.


Total aside - the advent calendar map WAY shifted from this. Is the next day going to be looking at a pyramid or mountain or something?


Time taken: 1 hour

My solutions for today's puzzles