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
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
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. ❤️