Commit af7df25d authored by Peter Fidelman's avatar Peter Fidelman
Browse files

Day 11

parent 3925023b
...@@ -172,3 +172,26 @@ After parsing the inputs with `go`, type `report` to get your answer. ...@@ -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. 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. 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.
\ No newline at end of file
variable (padend) : padend ( a ) (padend) @ ;
variable stride
128 constant fence 129 constant flash ; : ?special ( c -- f ) 128 and ;
: line>> ( a -- a n ) fence over c! 1+ dup -1 1 >> accept ;
: stride! ( n -- n ) dup 1+ stride ! ;
: get-lines ( -- )
pad begin line>> dup if stride! + 0 else drop -1 then until (padend) ! ;
: clamp ( a -- a' ) pad max padend min ;
: east ( a -- a' ) 1+ ; : west ( a -- a' ) 1- ;
: north ( a -- a' ) stride @ - ; : south ( a -- a' ) stride @ + ;
: for-grid ( xt -- ) padend pad do i over execute loop drop ;
: for-neighbors ( a xt -- a ) >r
dup north west r@ execute dup north r@ execute dup north east r@ execute
dup west r@ execute dup east r@ execute
dup south west r@ execute dup south r@ execute dup south east r> execute ;
: print-cell ( a -- ) c@
dup flash = if ." XX " drop else
dup fence = if ." || " drop else 48 - . then then ;
: increment-cell ( a -- ) clamp dup c@ dup ?special 0= if 1+ then swap c! ;
: fade-cell ( a -- ) dup c@ dup flash = if drop 48 then swap c! ;
variable #blinks
: ?will-blink ( c -- f ) 48 - 9 > ;
: blink ( a -- a ) flash over c! 1 #blinks +! ;
: compute-blink ( a -- a' ) clamp
dup c@ ?special if east exit then
dup c@ ?will-blink if blink ['] increment-cell for-neighbors north west
else east then ;
: compute-blinks ( -- ) pad begin compute-blink dup padend = until drop ;
: step ( -- )
['] increment-cell for-grid
compute-blinks
['] fade-cell for-grid ;
: go-11a ( n-steps -- )
0 #blinks ! get-lines 0 do step loop ." Answer:" #blinks @ . ;
: go-11b ( -- )
get-lines
0 begin 1+ 0 #blinks ! step stride @ 1- dup * #blinks @ = until
." Answer: " . ;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment