From bb9e613022a26460544b9bfa21a2465478e89255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kleszczy=C5=84ski?= Date: Sun, 8 Dec 2024 10:11:09 +0100 Subject: [PATCH] 2024 Day 08 --- 2024/d06/index.ts | 12 +- 2024/d08/index.ts | 180 ++++++++++++++++++ 2024/d08/input.txt | 50 +++++ 2024/d08/test-runs/0.txt | 12 ++ 2024/d08/test-runs/1.txt | 10 + .../combinations-without-repetition.ts | 23 +++ ts-core/combinatorics/index.ts | 1 + ts-core/types/Vec2.ts | 6 + ts-core/types/index.ts | 1 + 9 files changed, 289 insertions(+), 6 deletions(-) create mode 100644 2024/d08/index.ts create mode 100644 2024/d08/input.txt create mode 100644 2024/d08/test-runs/0.txt create mode 100644 2024/d08/test-runs/1.txt create mode 100644 ts-core/combinatorics/combinations-without-repetition.ts create mode 100644 ts-core/types/Vec2.ts create mode 100644 ts-core/types/index.ts diff --git a/2024/d06/index.ts b/2024/d06/index.ts index dc33261..baf28d8 100644 --- a/2024/d06/index.ts +++ b/2024/d06/index.ts @@ -19,24 +19,24 @@ const rotate = (speed: Vec2): Vec2 => { x: -1, y: 0, } - } - + } + // From going left to going upwards if (speed.x === -1 && speed.y === 0) { return { x: 0, y: -1, } - } - + } + // From going upwards to going right if (speed.x === 0 && speed.y === -1) { return { x: 1, y: 0, } - } - + } + // From going right to going downwards if (speed.x === 1 && speed.y === 0) { return { diff --git a/2024/d08/index.ts b/2024/d08/index.ts new file mode 100644 index 0000000..df3e6c7 --- /dev/null +++ b/2024/d08/index.ts @@ -0,0 +1,180 @@ +import { readFileSync } from 'node:fs' + +import { runExamples, runSolution } from '@magiczne/advent-of-code-ts-core/aoc' +import { combinationsWithoutRepetition } from '@magiczne/advent-of-code-ts-core/combinatorics' +import type { Vec2 } from '@magiczne/advent-of-code-ts-core/types' + +type Antenna = Vec2 & { type: 'Antenna'; code: string } +type Antinode = { type: 'Antinode'; code: string } +type MapItem = null | Antenna | Antinode +type Map = Array> + +interface Input { + map: Map + antennas: Record> +} + +const DEBUG = false +const printMap = (map: Map): void => { + if (!DEBUG) { + return + } + + map.forEach(row => { + let rowString = '' + + row.forEach(cell => { + if (cell.type === 'Antenna') { + rowString += cell.code + } else if (cell.type === 'Antinode') { + rowString += '#' + } else { + rowString += '.' + } + }) + + console.log(rowString) + }) + + console.log('') +} + +const part1 = (input: Input): number => { + const map = structuredClone(input.map) + + Object.values(input.antennas).forEach(antennaSet => { + combinationsWithoutRepetition(antennaSet, 2).forEach(([firstNode, secondNode]) => { + const distanceX = Math.abs(firstNode.x - secondNode.x) + const distanceY = Math.abs(firstNode.y - secondNode.y) + + const secondAntinodeDir: Vec2 = { x: firstNode.x < secondNode.x ? -1 : 1, y: firstNode.y < secondNode.y ? -1 : 1 } + const firstAntinodeDir: Vec2 = { x: firstNode.x < secondNode.x ? 1 : -1, y: firstNode.y < secondNode.y ? 1 : -1 } + + const antinodes: ReadonlyArray = [ + { + x: firstNode.x - firstAntinodeDir.x * distanceX, + y: firstNode.y - firstAntinodeDir.y * distanceY, + }, + { + x: secondNode.x - secondAntinodeDir.x * distanceX, + y: secondNode.y - secondAntinodeDir.y * distanceY, + }, + ] + + antinodes.forEach(antinode => { + if (map[antinode.y]?.[antinode.x] !== undefined) { + map[antinode.y][antinode.x] = { type: 'Antinode', code: firstNode.code } + } + }) + }) + }) + + printMap(map) + + return map + .map(row => { + return row.reduce((acc, item) => { + if (item?.type === 'Antinode') { + return acc + 1 + } + + return acc + }, 0) + }) + .reduce((acc, rowCount) => acc + rowCount, 0) +} + +const part2 = (input: Input): number => { + const map = structuredClone(input.map) + + Object.values(input.antennas).forEach(antennaSet => { + combinationsWithoutRepetition(antennaSet, 2).forEach(([firstNode, secondNode]) => { + const distanceX = Math.abs(firstNode.x - secondNode.x) + const distanceY = Math.abs(firstNode.y - secondNode.y) + + const secondAntinodeDir: Vec2 = { x: firstNode.x < secondNode.x ? -1 : 1, y: firstNode.y < secondNode.y ? -1 : 1 } + const firstAntinodeDir: Vec2 = { x: firstNode.x < secondNode.x ? 1 : -1, y: firstNode.y < secondNode.y ? 1 : -1 } + + let antinodes: Array = [] + + // Generate antinodes in first direction + for (let i = 1; ; i++) { + const x = firstNode.x - firstAntinodeDir.x * (distanceX * i) + const y = firstNode.y - firstAntinodeDir.y * (distanceY * i) + + if (map[y]?.[x] === undefined) { + break + } + + antinodes.push({ x, y }) + } + + // Generate antinodes in second direction + for (let i = 1; ; i++) { + const x = secondNode.x - secondAntinodeDir.x * (distanceX * i) + const y = secondNode.y - secondAntinodeDir.y * (distanceY * i) + + if (map[y]?.[x] === undefined) { + break + } + + antinodes.push({ x, y }) + } + + antinodes.forEach(antinode => { + if (map[antinode.y]?.[antinode.x] !== undefined) { + map[antinode.y][antinode.x] = { type: 'Antinode', code: firstNode.code } + } + }) + }) + }) + + printMap(map) + + return map + .map(row => { + return row.reduce((acc, item) => { + if (item !== null) { + return acc + 1 + } + + return acc + }, 0) + }) + .reduce((acc, rowCount) => acc + rowCount, 0) +} + +const reader = (file: string): Input => { + const map = readFileSync(file, 'utf-8') + .trim() + .split('\n') + .map((line, y) => { + return line.split('').map((item, x) => { + if (item === '.') { + return null + } + + return { + type: 'Antenna', + code: item, + x, + y, + } + }) + }) + + const antennas = Object.groupBy( + map.flatMap(row => { + return row.filter(item => item !== null) + }), + antenna => antenna.code, + ) + + return { + antennas: antennas as Record>, + map: map as Array>, + } +} + +runExamples(2024, '08', reader, part1, part2) +runSolution(2024, '08', reader, part1, part2) diff --git a/2024/d08/input.txt b/2024/d08/input.txt new file mode 100644 index 0000000..b245554 --- /dev/null +++ b/2024/d08/input.txt @@ -0,0 +1,50 @@ +..........................4..............7..q..... +..........G..42.f......K.........7................ +D.t...S......A.................................... +..K.................................I............. +G....D...f.tA..H.S..........o................N.... +t....f..............4..A........B.........N.....q. +...b...k....f..h..........6....................... +..........b....m................7...............Q. +....h....G.2........K.i........................... +.F...2.....D....H..6..o........I.................. +k.......b..................K......I.....e.....B... +.............Sp..o....n....R.............N........ +F............d................2................... +.........i........................................ +.....ma.....d......p.Q..n.....7....9..........N... +......m..H......S...8......n.....Q...e............ +.i..............8......O.....I................c... +..d......k....R.....................9....z........ +..p.......m......n...............P................ +.......pLb...................W..j................q +.....C..1..........u.....c.....jO...Z..o.........V +..C.....i........X1......9......e....j.....B....c. +......................9...........Q..Z............ +.d....h..L...............8........O............... +....C....r..L....R...............6................ +...........h.............1.t......P.......V....... +.......L.1........................................ +.................................................. +X.......................................V.....W... +rx........a.X.......0....l..........6.........z... +..r........a.8.................................z.. +................w.........l..............P....A... +..........E....s..w.j........l...............W.... +...v...............c..............W..y...V.O...... +.....X..g.Y...0w......l...................u....... +.C.......Y...0.................................... +...g..UJ...0........v............................. +.U...aY........................................... +....5........Y....MUJ..........B.................. +.......g...5M........J.......w.........u..Z....... +................TE................................ +..U....r....5.................J..........Z........ +.......5...3......s........T...................... +.............E.T..............................u... +...........v........y.......................P..... +................s................................. +x............M3........e.......................... +........3...v......MT............................. +.............x.................................... +....x..........3............y..................... \ No newline at end of file diff --git a/2024/d08/test-runs/0.txt b/2024/d08/test-runs/0.txt new file mode 100644 index 0000000..de0f909 --- /dev/null +++ b/2024/d08/test-runs/0.txt @@ -0,0 +1,12 @@ +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ \ No newline at end of file diff --git a/2024/d08/test-runs/1.txt b/2024/d08/test-runs/1.txt new file mode 100644 index 0000000..023061c --- /dev/null +++ b/2024/d08/test-runs/1.txt @@ -0,0 +1,10 @@ +T......... +...T...... +.T........ +.......... +.......... +.......... +.......... +.......... +.......... +.......... \ No newline at end of file diff --git a/ts-core/combinatorics/combinations-without-repetition.ts b/ts-core/combinatorics/combinations-without-repetition.ts new file mode 100644 index 0000000..d708903 --- /dev/null +++ b/ts-core/combinatorics/combinations-without-repetition.ts @@ -0,0 +1,23 @@ +const combinationsWithoutRepetition = (items: ReadonlyArray, length: number): ReadonlyArray> => { + const result: Array> = [] + + const backtrack = (combination: Array, start: number): void => { + if (combination.length === length) { + result.push([...combination]) + + return + } + + for (let i = start; i < items.length; i++) { + combination.push(items[i]) + backtrack(combination, i + 1) + combination.pop() + } + } + + backtrack([], 0) + + return result +} + +export { combinationsWithoutRepetition } diff --git a/ts-core/combinatorics/index.ts b/ts-core/combinatorics/index.ts index 4bc8643..19409f3 100644 --- a/ts-core/combinatorics/index.ts +++ b/ts-core/combinatorics/index.ts @@ -1 +1,2 @@ export { combinations } from './combinations' +export { combinationsWithoutRepetition } from './combinations-without-repetition' diff --git a/ts-core/types/Vec2.ts b/ts-core/types/Vec2.ts new file mode 100644 index 0000000..83bea16 --- /dev/null +++ b/ts-core/types/Vec2.ts @@ -0,0 +1,6 @@ +interface Vec2 { + x: number + y: number +} + +export type { Vec2 } diff --git a/ts-core/types/index.ts b/ts-core/types/index.ts new file mode 100644 index 0000000..556ad1f --- /dev/null +++ b/ts-core/types/index.ts @@ -0,0 +1 @@ +export type * from './Vec2'