Skip to content

Instantly share code, notes, and snippets.

@vlaurin
Created December 3, 2023 22:14
Show Gist options
  • Save vlaurin/14f5706ddc425f158dec5eb463dfd2ba to your computer and use it in GitHub Desktop.
Save vlaurin/14f5706ddc425f158dec5eb463dfd2ba to your computer and use it in GitHub Desktop.
Advent of code 2023 - Day 3
import {readFileLines} from '../utils/file.mjs';
const NUMBER_REGEX = /\d+/g;
const extractNumbers = (line, lineIndex) => {
const numbers = [];
let match;
while ((match = NUMBER_REGEX.exec(line)) != null) {
numbers.push({
number: match[0],
neighbours: getNeighbours(lineIndex, match.index, match[0]),
});
}
return numbers;
}
const getNeighbours = (lineIndex, firstCharIndex, number) => [
coord(lineIndex - 1, firstCharIndex - 1),
coord(lineIndex, firstCharIndex - 1),
coord(lineIndex + 1, firstCharIndex - 1),
...Array.from(number).flatMap((digit, index) => [
coord(lineIndex - 1, firstCharIndex + index),
coord(lineIndex + 1, firstCharIndex + index),
]),
coord(lineIndex - 1, firstCharIndex + number.length),
coord(lineIndex, firstCharIndex + number.length),
coord(lineIndex + 1, firstCharIndex + number.length),
];
const coord = (line, char) => ({line, char});
const hashCoord = (coord) => JSON.stringify(coord);
const charExtractor = (lines) => (coord) => lines[coord.line]?.charAt(coord.char);
const isPart = (getChar) => (number) => number.neighbours.map(getChar).some(isSymbol);
const isSymbol = (char) => char && !Number(char) && char !== '.';
const addPartNumber = (sum, part) => sum + Number(part.number);
const indexGears = (getChar) => (gears, part) => {
const gearCoords = part.neighbours.filter((coord) => isGear(getChar(coord)));
if (!gearCoords.length) {
return gears;
}
return {
...gears,
...Object.fromEntries(
gearCoords.map(hashCoord)
.map((hash) => [hash, gears[hash] ? new Set([...gears[hash], part]) : new Set([part])])
),
};
};
const isGear = (char) => char === '*';
const hasTwoParts = (parts) => parts.size === 2;
const computeRatio = (parts) => Array.from(parts)
.map((part) => Number(part.number))
.reduce(Math.imul, 1);
const main = async () => {
const lines = readFileLines(process.argv[2]);
const getChar = charExtractor(lines);
const parts = lines.flatMap(extractNumbers)
.filter(isPart(getChar));
// Part 1 answer
const partsSum = parts.reduce(addPartNumber, 0);
const gears = parts.reduce(indexGears(getChar), {});
// Part 2 answer
const ratioSum = Object.values(gears)
.filter(hasTwoParts)
.map(computeRatio)
.reduce((x, y) => x + y, 0);
console.log(partsSum);
console.log(ratioSum);
};
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment