Day 1/2021 - Sonar Sweep

The first puzzle of 2021's AoC (available at https://adventofcode.com/2021/day/1) kicks off with a crisis: an elf has accidentally knocked Santa's sleigh keys into the ocean. Fortunately, we have a submarine for just such emergencies — covered in Christmas lights, naturally.

The submarine's sonar gives us depth measurements. We need to analyze how quickly the sea floor depth increases.

Parsing the Input

The input is simply one number per line:

const processInput = (day: number): number[] => {
    const lines = readInputLines(day);
    return lines.map(line => parseInt(line, 10));
};

Always specify the radix (10) with parseInt. JavaScript can get weird with leading zeros otherwise.

Part One: Counting Increases

Count how many times the depth measurement increases from one reading to the next.

const partOne = (input: number[], debug: boolean) => {
    let count = 0;
    
    for (let i = 1; i < input.length; i++) {
        if (input[i] > input[i - 1]) {
            count++;
        }
    }
    
    return count;
};

Starting the loop from index 1 (not 0) because we're comparing each element to its predecessor. GitHub Copilot actually guessed this pattern when I started typing — it recognized the "start from 1" idiom as a comparison pattern.

Part Two: Sliding Windows

Part two introduces a sliding window: instead of comparing individual measurements, compare the sum of three consecutive measurements.

First, create the windows:

const partTwo = (input: number[], debug: boolean) => {
    // Create sliding window sums
    const windows: number[] = [];
    for (let i = 2; i < input.length; i++) {
        windows.push(input[i] + input[i - 1] + input[i - 2]);
    }
    
    // Count increases (same logic as part one)
    let count = 0;
    for (let i = 1; i < windows.length; i++) {
        if (windows[i] > windows[i - 1]) {
            count++;
        }
    }
    
    return count;
};

We start from index 2 because we need two previous elements to form a complete window. From 2000 input values, we get 1998 windows.

I keep part one and part two independent — I could refactor the counting logic into a shared function, but I prefer each part to be self-contained. Makes debugging easier and lets me run them independently.

The Excel Solution

For a linear list of numbers, sometimes Excel is the right tool:

Part One:

  • Column A: input values
  • Column B: =A2-A1 (difference from previous)
  • Result: =COUNTIF(B:B,">0")

Part Two:

  • Column C: =A1+A2+A3 (sliding window sum)
  • Column D: =C2-C1 (difference)
  • Result: =COUNTIF(D:D,">0")

Both solutions gave the same answers: 1602 and 1633. Sometimes you don't need code at all — but the TypeScript solution is more reusable and scriptable.

Off-By-One Awareness

These problems are ripe for off-by-one errors:

  • 2000 input values → 1999 comparisons (part one)
  • 2000 input values → 1998 windows → 1997 comparisons (part two)

Excel actually helps here because you can see exactly which cells have data and which don't. In code, you need to think carefully about your loop bounds.

Takeaways

  1. Start loops from 1 when comparing to previous: The idiom for (let i = 1; ...) signals "I need the previous element."

  2. Sliding windows start later: If your window needs N previous elements, start from index N-1.

  3. Keep parts independent: Copy-paste between parts rather than sharing code. It's redundant but simpler to debug.

  4. Excel is underrated: For one-off linear computations, a spreadsheet can be faster than writing code. No shame in using the right tool.

  5. Always verify input parsing: Before solving anything, log your parsed input and compare to the source. Wrong parsing = wrong answer, always.

The full solution is available in the repository.