I too went strange places with part 2. Basically, I realized you could use the last line with the operations to determine the width of each column of numbers, and used that to break apart each line into substrings and turned each column into a list, so the sample input ended up looking like
Then I turned each sublist into a list of numbers by walking each one once per column in it with a lot of string-ref's to extract digits. Using string->list would have looked more elegant but I bet my way ended up using less memory. (Plus I didn't think of it until skimming these posts.) Anyway once I had the numbers I just reused the same part1 from above on them.
Part 2 I extended the same reasoning with a hash table counting the number of beams in each tile and a transfer function for each kind of input character.
For me today was a big lesson in keeping it simple. I did a lot of thinking about k-d trees and grids before staring at the ceiling for a few minutes, going "wait a second... this isn't that much" and just brute-forcing it (with some pretty ugly code).
If it works, who's to complain? Well done on seeing the forest for the k-d trees.
Haha, I think the misdirect was the point of today. I got pretty frustrated due to my poor reading comprehension and came up with two different but equally wrong solutions before I erased everything and started over.
I too wasted much time with fancy complicated graph algorithm approaches before figuring out a simpler way that was fast. And I just realized I could have used a sorted list of distances instead of the priority queue I did use to make it simpler (But it's a library I wrote so a bit of dog-fooding going on there)...
Just picked up a new game (Octopath Traveller 0) so I have a feeling I might be done with AoC this year with my free time going towards playing it instead.
First version used for*/fold instead of a complicated named let, but I found out that in-vector doesn't play well with TR without an inst wrapper around it, and the optimization coach warns about that and not being able to optimize it.
My day 9 part 2 was absolutely disastrous! I got it somewhat working after reading up on polygon intersection on Wikipedia, but it was still wrong for many hours and many tries.
Then, I realized I would need powerful debugging tools, since everything was passing the test/sample but failing with the real input.
The simplest way I thought of doing so was to manually (vim-ing) convert the input to an SVG using <path>, and overlay the solutions my program was outputting with a simple <rect>.
This led to a big aha! moment...
Big spoilers! Problem visualization!
In my solution I was only checking the corners of the solution were inside the polygon. But I needed to check the edges didn't intersect anything as well!
Yeah, today was the first day where I felt the need to "see" the problem, but once I busted out plot it felt a bit like cheating, because I could get away with a less general but sufficient solution.
All in all, a very fun puzzle; I got to use a macro, and one of my favourite websites from back when I was in school, geometryalgorithms.com, for the winding-number procedure, which I've used in previous Advents to great effect.
Using in-combinations makes things a bit cleaner (and faster, I suspect), which would've been useful on day 8 as well, but I had forgotten about it.
Spoilers
; day 9
; part 1
(for/fold ([best -inf.0])
([pair (in-combinations red-tiles 2)])
(max best (apply area pair)))
; part 2
(for/fold ([best -inf.0])
([pair (in-combinations red-tiles 2)]
#:do [(define r (apply bounds pair))]
#:when (andmap in-polygon? (rectangle-frame r))
#:unless (bisected? (rectangle-around? r)))
(max best (rectangle-area r)))
; day 8
(define pairwise-distances
(sort
#:key car
(for/list ([pair (in-combinations junctions 2)])
(cons (apply distance pair) pair))
<))
As an aside, I started using complex numbers because I thought they would be useful when calculating areas, but I couldn't quite get the calculations to work, so I ended up deconstructing them anyhow. They were useful for the interpolation, though, which was fortunate.
Edit: I realized the area comparison could be reordered to speed it up a bit.
Spoilers
(time
(for/fold ([best -inf.0])
([pair (in-combinations red-tiles 2)]
#:do [(define r (apply bounds pair))]
#:when (< best (rectangle-area r))
#:when (andmap in-hull? (rectangle-corners r))
#:unless (hull-bisects? (rectangle-contains? r)))
(rectangle-area r)))
;=> cpu time: 1343 real time: 1383 gc time: 468
Although this doesn't show the optimization for interpolated points, which I also realized only really needed to be calculated once.
I solved part 1 with your run of the mill recursive search, but part 2 just murdered my algorithms. I absolutely couldn't get it to run fast enough.
I suppose I am missing some cool termination conditions, some form of symmetry in the problem space, or some kind of partitioning/dynamic programming that allows me to split the problem in smaller ones and solve/reuse those.
I ended up solving part 2 with CP-SAT, so no Racket (tried to use csp but it was just a tad too slow with the constraints I could come up with).
Day 11 was pretty good though, after I figured out it was a DAG. Maybe it was said explicitly in the prompt, but I kind of skimmed over it.
It is one of the cutest solutions yet for me (not sure if fft->dac being the right path is for every input):