Day 10

prelude

https://adventofcode.com/2024/day/10

import { grid, inputDay, maybeNumber } from "./lib/utilities.js"
const parser = inp => grid(inp).map(row => row.map(maybeNumber))
const test = parser(`89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732`)

const input = await inputDay(10, { parser })
display(test)
display(input)

// our coördinate system is [row, col], where decreasing y goes up
const N = [-1, 0]
const E = [0, 1]
const S = [1, 0]
const W = [0, -1]

part 1

A function to score a single trailhead

function score(map, trailhead) {
  let frontier = [trailhead]
  let points = new Set([])
  while (frontier.length > 0) {
    const [y, x] = frontier.pop()
    const val = map[y][x]
    if (val == 9) points.add(String([y, x]))
    frontier = frontier.concat(
      [N, E, S, W]
        .map(([dy, dx]) => {
          return map[y + dy]?.[x + dx] == val + 1 ? [y + dy, x + dx] : false
        })
        .filter(Boolean),
    )
  }
  return points.size
}
display(score(test, [0, 2]))

A function to find all trailheads, score them, and sum them

function total(map, score) {
  return map
    .flatMap((row, y) => row.map((e, x) => (e == 0 ? [y, x] : false)))
    .filter(Boolean)
    .map(pt => score(map, pt))
    .reduce((a, b) => a + b)
}
display(total(test, score))
display(total(input, score))

part 2

for part 2, count the number of times we reach a 9 rather than the number of 9s we reach

function score2(map, trailhead) {
  let frontier = [trailhead]
  let score = 0
  while (frontier.length > 0) {
    const [y, x] = frontier.pop()
    const val = map[y][x]
    if (val == 9) score++
    frontier = frontier.concat(
      [N, E, S, W]
        .map(([dy, dx]) => {
          return map[y + dy]?.[x + dx] == val + 1 ? [y + dy, x + dx] : false
        })
        .filter(Boolean),
    )
  }
  return score
}
display(score2(test, [0, 2]))

We can use the same total score function

display(total(test, score2))
display(total(input, score2))

visualization

for kicks, here's a joy division plot of the map

const chart = Plot.plot({
  x: { axis: null },
  y: { axis: null },
  marks: [
    input.map((row, y) =>
      Plot.lineY(row, {
        x: (_, i) => i,
        y: d => d * 2 + y * 10,
        curve: "basis",
        strokeWidth: 1,
      }),
    ),
  ],
})
display(chart)