From a29299ede8728111257b9ae734a5ef227acf58d2 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Sun, 3 Dec 2023 12:17:08 +0000 Subject: [PATCH] Day Three completed --- src/day_three.test.ts | 4 ++ src/day_three.ts | 105 ++++++++++++++++++++++++------------------ src/utils.ts | 7 +++ 3 files changed, 71 insertions(+), 45 deletions(-) create mode 100644 src/utils.ts diff --git a/src/day_three.test.ts b/src/day_three.test.ts index ca6f940..93c6f0d 100644 --- a/src/day_three.test.ts +++ b/src/day_three.test.ts @@ -20,4 +20,8 @@ describe('Day Three', () => { const engine = Engine.create(schematic); expect(engine.sumPartNumbers()).toEqual(4361); }); + it('should give the sum of the gear ratios', () => { + const engine = Engine.create(schematic, true); + expect(engine.gearRatioSums()).toEqual(467835); + }); }); \ No newline at end of file diff --git a/src/day_three.ts b/src/day_three.ts index fcac7c8..2af7074 100644 --- a/src/day_three.ts +++ b/src/day_three.ts @@ -1,75 +1,90 @@ import { takeWhile } from 'lodash'; import fs from "fs"; -import {calculateMinimumCubePowers, calculatePossibleGames, parseGame} from "./day_two"; +import {matchAllAndThen} from "./utils"; export class Engine { - constructor(private readonly partNumbers: number[]) { + constructor(private readonly parts: number[][], private readonly schematic: string[][]) { } - public static create(input: string): Engine { + public static create(input: string, gearsOnly: boolean = false): Engine { const lines = input.split('\n').filter(Boolean); const partRegex = /\d+/g; - const symbolRegex = /[^a-zA-Z\d\.]/g; + const symbolRegex = gearsOnly ? /\*/g : /[^a-zA-Z\d\.]/g; const parts : number[][] = new Array(lines.length).fill(0).map(() => new Array(lines[0].length)); const symbols: string[][] = new Array(lines.length).fill(0).map(() => new Array(lines[0].length)); lines.forEach((line, lineNumber) => { - const matches = [...line.matchAll(partRegex)]; - matches.map(match => { - if (match && match.index !== undefined) { - const parsedNumber = parseInt(match[0], 10); - for (let i = match.index; i < match.index + match[0].length; i++) { - parts[lineNumber][i] = parsedNumber; - } + matchAllAndThen(line, partRegex, (match, index) => { + const parsedNumber = parseInt(match, 10); + for (let i = index; i < index + match.length; i++) { + parts[lineNumber][i] = parsedNumber; } }); }); lines.forEach((line, lineNumber) => { - const matches = [...line.matchAll(symbolRegex)]; - - matches.map(match => { - if (match && match.index !== undefined) { - symbols[lineNumber][match.index] = match[0]; - } - }); + matchAllAndThen(line, symbolRegex, (match, index) => symbols[lineNumber][index] = match); }); - console.log(symbols.length, parts.length) - const partsList = symbols.flatMap((row, rowIndex) => - row.map((symbol, index) => { - if (!symbol) return symbol; - - const partIndex = [ - [rowIndex - 1, index - 1], - [rowIndex - 1, index], - [rowIndex - 1, index + 1], - [rowIndex, index - 1], - [rowIndex, index + 1], - [rowIndex + 1, index - 1], - [rowIndex + 1, index], - [rowIndex + 1, index + 1] - ]; - return Array.from(new Set(partIndex.filter(([rowNum, col]) => rowNum >= 0 && rowNum <= symbols.length && index >= 0 && index <= row.length) - .map(([rowNum, column]) => { - return parts[rowNum][column] - }).filter(Boolean))) - .reduce((total, val) => total + val,0); - }) - ) - - return new Engine(partsList as number[]); + return new Engine(parts, symbols); } public sumPartNumbers(): number { - return this.partNumbers.reduce((total, partNumber) => total + partNumber, 0); + const partsList = this.schematic.flatMap((row, rowIndex) => + row.map((symbol, index) => { + if (!symbol) return symbol; + + const partIndex = [ + [rowIndex - 1, index - 1], + [rowIndex - 1, index], + [rowIndex - 1, index + 1], + [rowIndex, index - 1], + [rowIndex, index + 1], + [rowIndex + 1, index - 1], + [rowIndex + 1, index], + [rowIndex + 1, index + 1] + ]; + return Array.from(new Set(partIndex.filter(([rowNum, col]) => rowNum >= 0 && rowNum <= this.schematic.length && index >= 0 && index <= row.length) + .map(([rowNum, column]) => { + return this.parts[rowNum][column] + }).filter(Boolean))) + .reduce((total, val) => total + val,0); + }) + ) as number[]; + return partsList.reduce((total, partNumber) => total + partNumber, 0); + } + + public gearRatioSums(): number { + return this.schematic.flatMap((row, rowIndex) => + row + .map((symbol, index) => { + const partIndex = [ + [rowIndex - 1, index - 1], + [rowIndex - 1, index], + [rowIndex - 1, index + 1], + [rowIndex, index - 1], + [rowIndex, index + 1], + [rowIndex + 1, index - 1], + [rowIndex + 1, index], + [rowIndex + 1, index + 1] + ]; + return Array.from(new Set(partIndex.filter(([rowNum, col]) => rowNum >= 0 && rowNum <= this.schematic.length && index >= 0 && index <= row.length) + .map(([rowNum, column]) => { + return this.parts[rowNum][column] + }).filter(Boolean))) + }) + ).filter(list => list.length === 2) + .reduce((total, [a, b]) => { + return total + (a * b) + }, 0); } } export const runDayThree = () => { const input = fs.readFileSync('./inputs/day_three_input.txt', 'utf8'); - const engine = Engine.create(input) - console.log(engine.sumPartNumbers()); + console.log(Engine.create(input).sumPartNumbers()) + console.log(Engine.create(input, true).gearRatioSums()) + } \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..ffd7f0c --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,7 @@ +export const matchAllAndThen = (input: string, pattern: RegExp, callback: (value: string, index: number) => void) => { + [...input.matchAll(pattern)].map(match => { + if (match && match.index !== undefined) { + callback(match[0], match.index); + } + }); +} \ No newline at end of file