@@ -172,3 +172,26 @@ After parsing the inputs with `go`, type `report` to get your answer.
Heh, I knew there was a reason to write an `?empty` function for my stack in Part A, even though it wasn't needed yet. Getting the matching delimiters is as simple as popping them off this stack until it's empty.
The highlight (or rather lowlight) of the problem is calculating the median score. Because there are not many scores, I avoided doing anything clever... I just laid all of the scores into the dictionary with `,` and then made a very nasty O(N^2) algorithm that walks that list n/2 times eliminating the minimum value. The lowest survivor is the median.
# Day 11
## Part A
This is a very similar kind of grid problem as Day 9, so I'll use same kind of delimited grid. Normal grid values will be `48`-`58` (ASCII '0'-'9'). There are two special values: `128` to mark a flash and `129` for the board delimiter. Both special values have the high bit set to make them easier to detect.
To move around on the grid we use the words `north`, `south`, `east`, `west` to move one square in each direction relative to the current address. These chain, so you can call e.g. `north east` to move diagonally. Don't forget to `clamp` to the board dimensions before using this address for anything.
Each simulation step can be broken into two phases: `increment-cell` and `compute-blinks`, whose purpose is obvious from the problem description. Because I am using a placeholder value to prevent duplicate flashes, I wind up with a third phase `fade-cell` whose purpose is to fade the `128` (flashes) back to `48` (zeroes) that are ready to be incremented next step.
`compute-blinks` could have been implemented several different ways:
- **multiple passes per sim step**: cursor performs one pass through the board blinking octopuses and charging neighbors, then starts again at the top left of board, repeatedly, until it does one full pass without anyone blinking. When that happens, it means we're done with the current sim step and can move on to the next step. This is the clearest way of solving the problem but also the slowest and most cumbersome.
- **recursion**: this leads to an explosion of traversing cursors with no real benefit.
- **one pass with rewind**: after a blink, charge neighbors then rewind to northwest neighbor and resume.
"one pass with rewind" is the method I used.
The part of the solution I'm most proud of is the board traversal functions. I knew I was going to be traversing the board many times for different reasons, so I factored out the traversal code as `for-grid` and `for-neighbors`. `for-grid` in particular is re-used throughout the program, and during development it gave me the handy ability to run `' print-cell for-grid` straight from the REPL.
## Part B
Change the loop boundary condition and you're done. This was so similar to Part A that I combined both answers into a single file.