Day 2

prelude

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

import { inputDay, munge } from "./lib/utilities.js"
const inp = await inputDay(2)
display(inp)

The graph isn't very useful, but here's how the numbers are distributed

Part 1

We can test that every element of an array is increasing with every:

display(
  [1, 2, 3, 4, 5].every((e, i, arr) => {
    return i == 0 || (e > arr[i - 1] && e - arr[i - 1] < 4)
  }),
)

And verify that it gives the results as expected on the demonstration:

const test = munge(`7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9`)
display(
  test.map(
    row =>
      row.every(
        (e, i, arr) => i == 0 || (e < arr[i - 1] && arr[i - 1] - e < 4),
      ) ||
      row.every(
        (e, i, arr) => i == 0 || (e > arr[i - 1] && e - arr[i - 1] < 4),
      ),
  ),
)

Let's give those complicated conditionals names:

function decreasing(e, i, arr) {
  return i == 0 || (e < arr[i - 1] && arr[i - 1] - e < 4)
}

function increasing(e, i, arr) {
  return i == 0 || (e > arr[i - 1] && e - arr[i - 1] < 4)
}

And count the number of rows that match:

inp.map(row => row.every(decreasing) || row.every(increasing)).filter(Boolean)
  .length

We can graph it to show that the increasing or decreasing rows are clustered at the end of the list

Part 2

For part 2, we can't just use every any longer, we need to test if removing any element makes the row safe. We can write our own version of every, which pulls out elements one by one and tests if the resulting array is safe:

// return a new array without element `i`
function cut(arr, i) {
  return arr.slice(0, i).concat(arr.slice(i + 1, arr.length))
}

function everyButOne(arr, f) {
  if (arr.every(f)) return true
  return arr.some((e, i, a) => cut(a, i).every(f))
}

Again, we can validate against the test input:

test.map(row => everyButOne(row, decreasing) || everyButOne(row, increasing))

And finally, run against the real input

inp
  .map(row => everyButOne(row, decreasing) || everyButOne(row, increasing))
  .filter(Boolean).length

Graphing the rows that match everyButOne but not every shows that a few new rows in the first 600 now match