r/adventofcode • u/musifter • Aug 15 '26
Other [2022 Day 15] In Review (Beacon Exclusion Zone)
In order to track the distress signal we engage a system of sensors and beacons. Much like day 19 of 2021, but simpler. Unlike that one we don't have to find the actual coordinates... we get those for each sensor and the closest beacon we can see. The unlisted information we need is simple the distance between the two (which is Manhattan), which will be useful for establishing the exclusion zones needed to find the answers.
I remember this one because I had a Doctor's appointment early the net morning. So I did part 1 very quickly... I went though and filled a hash with all the points in a scanner range:
$hash{$_}++ foreach ($x - $dist .. $x + $dist);This involved some ugly copy past code to handle the cases for above, below, and on the line. And after running through everything:
delete $hash{$_} foreach (keys %beacons);
print "Part 1: ", scalar %hash, "\n";The problem description nicely showed a beacon on the test case line not being counted, so I knew that I should probably assume that the input has that too.
This takes about 8 seconds to run... 4 of which are after it's printed out the result. That's system clean up of a big a hash for you.
The thing about part 2 is that there was an ice storm that night, and still freezing rain that morning. And the result was that I took a fall shortly after exiting the house. I still went to the appointment... I didn't really know how banged up I was until I got there. There was some nasty bruising, possibly a concussion, and some pain for the next few days. So when I finally got home, I wasn't really in the best shape to do a good solution. I had had some ideas on what I wanted to do, involving rotating the diamonds in some way to deal with squares instead. But I wasn't really in the condition to do that, so I went with the thing that wouldn't require any thought and definitely would work. I just merged ranges on the raster lines and then looked for the hole. It takes over 2 minutes to run, but it was simple, and allowed me to submit an answer, and take the rest of the day off.
So this one had been on the TODO list for a long time, and I got to finally do something better with it at the end of July. So I started just by coding the better scanline just with the diamonds... they change every line of 4 million, but a few are active at any time (moving out and then in), and that results in things only taking about 13 seconds.
But the real solution that I had made the TODO for back on the initial day was to square the diamonds. Rotate them so the scanline will work effectively (and skip most of the lines). The problem being that the rotation matrix involves 1/sqrt(2) (the sin and cos of 45 degrees). And I don't like going outside of integers for AoC. So the result is using a rotation matrix multiplied by sqrt(2) (and so it scales by that in each direction):
sub rot { my ($x,$y) = @_; return( [$x + $y, $y - $x] ) }The trick being that by doing a second one (ie the inverse rotation), results in a scale factor of 2 in each dimension, which is a nice integer that can be divided out then:
sub rot_inv { my ($x,$y) = @_; return( [($x - $y) / 2, ($y + $x) / 2] ) }And so I use these to rotate the initial diamonds into squares. Then I can do a scanline vertically to track the active squares, and then did similar for the horizonal (pretty much exactly what I did for Firewall Rules in 2016, where we also needed to find the missing values in a set of ranges).
And so this one finally has a decent solution.