Skip to content

Advent of Code 2023 Day Three

Published: at 06:29 PM

Here’s my solution to Day Three of Advent of Code.

Part 1

Today I reused a good bit of Part One on Part Two.

const testInput = `467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..`;

const NUM_REGEX = /\d+/g;
let specialCharacters = /[^a-zA-Z0-9.]/g;

const parseInput = input => {
  const numberPositions = [];
  const specialCharPositions = [];

  input.split("\n").forEach((line, row) => {
    let match;

    while ((match = NUM_REGEX.exec(line)) !== null) {
      numberPositions.push({
        x: match.index,
        y: row,
        number: parseInt(match[0]),
        length: match[0].length,
      });
    }

    NUM_REGEX.lastIndex = 0;

    while ((match = specialCharacters.exec(line)) !== null) {
      specialCharPositions.push({
        x: match.index,
        y: row,
        char: match[0],
      });
    }

    specialCharacters.lastIndex = 0;
  });

  return [numberPositions, specialCharPositions];
};

const findAdjacentNumbers = (specialCharPositions, numberPositions) => {
  const numberList = [];

  numberPositions.forEach(number => {
    const numberEnd = number.x + number.length;
    if (
      specialCharPositions.some(
        specialChar =>
          specialChar.x >= number.x - 1 &&
          specialChar.x <= numberEnd &&
          specialChar.y >= number.y - 1 &&
          specialChar.y <= number.y + 1
      )
    ) {
      numberList.push(number.number);
    }
  });

  return numberList.reduce((a, b) => a + b, 0);
};

const [numberPositions, specialCharPositions] = parseInput(input);
console.log(findAdjacentNumbers(specialCharPositions, numberPositions)); // 4361

Part 2

// here I just reassigned the special characters variable
// so that I could reuse most of part one
specialCharacters = /[*]/g;

const calculateSumOfGearRatio = (gearPositions, numberPositions) => {
  const numberList = gearPositions.map(gear => {
    const adjacentNumbers = numberPositions
      .filter(number => {
        const numberEnd = number.x + number.length;
        return (
          gear.x >= number.x - 1 &&
          gear.x <= numberEnd &&
          gear.y >= number.y - 1 &&
          gear.y <= number.y + 1
        );
      })
      .map(number => number.number);

    return adjacentNumbers.length === 2
      ? adjacentNumbers.reduce((a, b) => a * b, 1)
      : 0;
  });

  return numberList.reduce((a, b) => a + b, 0);
};
const [numberPositionsPart2, gearPositions] = parseInput(testInput);
console.log(calculateSumOfGearRatio(gearPositions, numberPositionsPart2)); //467835

I really had to think about this one. For some reason I’ve always had a hard time mentally visualizing 2D array operations. Also, I wrote my RegEx for Part One poorly the first time and was missing a ton of entries. 🤦