Advent of Code (in MiniScript), Day 8

JoeStrout - Dec 8 '22 - - Dev Community

Last night was Day 8 of the annual Advent of Code programming contest. As usual, I tackled it in MiniScript.

In this challenge, we're given a grid of digits (0-9) representing the height of trees in a forest. The elves first want to figure out which trees are visible from outside the woods — that is, not blocked by some equally tall or taller tree to the north, south, east, or west.

Here's my solution:

fname = "input.txt"

grid = file.readLines(fname)
if not grid[-1] then grid.remove -1
width = grid[0].len
height = grid.len
print "width: " + width + ", height: " + height

isVisInDir = function(x,y, dx,dy)
    h = grid[y][x]
    while true
        x = x + dx
        y = y + dy
        if x < 0 or x >= width or y < 0 or y >= height then
            return true
        end if
        if grid[y][x] >= h then return false
    end while
end function

isVisible = function(x,y)
    return isVisInDir(x,y, -1,0) or
        isVisInDir(x,y, 1,0) or
        isVisInDir(x,y, 0,-1) or
        isVisInDir(x,y, 0,1)
end function

count = 0
for x in range(0, width-1)
    for y in range(0, height-1)
        if isVisible(x,y) then count = count + 1
    end for
end for
print "final answer (part A): " + count
Enter fullscreen mode Exit fullscreen mode

I scrapped my usual read-each-line loop for a file.readLines, which reads the whole thing at once, returning a list of strings. This included an extra blank line at the end, so I checked for and removed that, and then printed the width and height as a sanity check.

The real work here is done by the isVisInDir function, which takes the (x,y) coordinates of a spot in the grid, and a (dx,dy) direction to check in. It uses a loop to repeatedly add those dx,dy values to the x,y values, so as to consider each tree in turn along that line. If find a tree (digit) equal to or greater than the one at x,y, we return false (our starting tree is not visible from this direction). If we go out of bounds, then we return true.

With that in hand, the isVisible function simply checks all four directions. Finally, we have a simple counting loop that calls this for each point in the grid. (Instead of an if statement, I could have just done count = count + isVisible(x,y), since boolean values in MiniScript are just 0 and 1.)

Part B

In the second part of the challenge, the elves want to find the tree with the best view. The "scene score" of a tree is defined as the product of how far you can see in each of the 4 directions.

To solve this, I copied my isVisInDir function and modified it into a viewDist function. But the basic idea is the same: walk in direction (dx,dy) until we go out of bounds or hit a sufficiently large value. But as we go, we count how many steps we took, representing the view distance in that direction.

Then, I copied isVisible to make a new scenicScore function, which multiplies the viewDist of each direction. And finally, instead of a counting loop, I have a loop at the end that just iterates over all trees and keeps track of the maximum score. The new code added is shown below.

viewDist = function(x, y, dx, dy)
    h = grid[y][x]
    d = 0
    while true
        x = x + dx
        y = y + dy
        if x < 0 or x >= width or y < 0 or y >= height then break
        t = grid[y][x]
        d = d + 1
        if t >= h then break
    end while
    return d
end function

scenicScore = function(x,y)
    return viewDist(x,y, -1,0) *
        viewDist(x,y, 1,0) *
        viewDist(x,y, 0,-1) *
        viewDist(x,y, 0,1)
end function

bestScore = 0
for x in range(0, width-1)
    print "x=" + x + "..."
    for y in range(0, height-1)
        score = scenicScore(x,y)
        if score > bestScore then bestScore = score
    end for
end for

print "final answer (part B): " + bestScore
Enter fullscreen mode Exit fullscreen mode

It's a fair amount of code, but it was pretty quick to write; it took me 14 minutes overall, for a rank of 289 (a new personal best!).

Once again, my starter program did me no good; nor did I need any of the stuff I've been gathering in my custom aoc module, or even the standard /sys/lib modules. The solution was plain, unadorned MiniScript. ❤️

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .