Solution for Advent of Code (AoC) 2023 Day 3: Gear Ratios in JavaScript:

import fs from "fs";
import { log } from "console";

const lines = fs.readFileSync("./day3.txt", { encoding: "utf-8" }).split("\n");

function isDigit(c) {
  return /[\d]/.test(c);
}

function part1() {
  let sum = 0;

  for (const [rowIndex, line] of lines.entries()) {
    let partNumber = '';
    let startColIndex = 0;

    for (const [colIndex, c] of line.split('').entries()) {

      if (isDigit(c)) {
        if (!partNumber) {
          startColIndex = colIndex;
        }

        partNumber += c;
      }

      const isEndOfPartNumber = !isDigit(c) || (colIndex === line.length - 1)
      if (isEndOfPartNumber && partNumber) {

        const startRowSearchIndex = Math.max(rowIndex - 1, 0);
        const endRowSearchIndex = Math.min(rowIndex + 1, lines.length - 1);
        const startColSearchIndex = Math.max(startColIndex - 1, 0);
        const endColSearchIndex = Math.min(colIndex, line.length - 1)

        let symbolFound = false;
        for (let i = startRowSearchIndex; i <= endRowSearchIndex; i++) {
          for (let j = startColSearchIndex; j <= endColSearchIndex; j++) {
            if (/[^\d\.]/.test(lines[i][j])) {
              symbolFound = true;
            }
          }
        }

        if (symbolFound) {
          sum += Number(partNumber);
        }

        partNumber = '';
      }
    }
  }

  log(sum)
}

function part2() {
  let sum = 0;

  const gearMap = {};

  for (const [rowIndex, line] of lines.entries()) {
    let partNumber = '';
    let startColIndex = 0;

    for (const [colIndex, c] of line.split('').entries()) {

      if (isDigit(c)) {
        if (!partNumber) {
          startColIndex = colIndex;
        }

        partNumber += c;
      }

      const isEndOfPartNumber = !isDigit(c) || (colIndex === line.length - 1)
      if (isEndOfPartNumber && partNumber) {

        const startRowSearchIndex = Math.max(rowIndex - 1, 0);
        const endRowSearchIndex = Math.min(rowIndex + 1, lines.length - 1);
        const startColSearchIndex = Math.max(startColIndex - 1, 0);
        const endColSearchIndex = Math.min(colIndex, line.length - 1)

        for (let i = startRowSearchIndex; i <= endRowSearchIndex; i++) {
          for (let j = startColSearchIndex; j <= endColSearchIndex; j++) {
            if (/\*/.test(lines[i][j])) {
              const key = `${i}-${j}`;
              if (gearMap[key]) {
                sum += gearMap[key] * Number(partNumber);
              }

              gearMap[key] = Number(partNumber);
            }
          }
        }

        partNumber = '';
      }
    }
  }

  log(sum)
}

part1();
part2();