From 205086e7dde92eac1fae22fb695b08640f01f66d Mon Sep 17 00:00:00 2001 From: wieerwill Date: Wed, 20 Dec 2023 18:04:16 +0100 Subject: [PATCH] solved Day19 in TS --- Day19/ts/solution.ts | 91 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Day19/ts/solution.ts diff --git a/Day19/ts/solution.ts b/Day19/ts/solution.ts new file mode 100644 index 0000000..909a58b --- /dev/null +++ b/Day19/ts/solution.ts @@ -0,0 +1,91 @@ +import * as fs from 'fs'; + +type Range = [number, number]; +type WorkflowRule = [string, string, number, string]; +type WorkflowRules = WorkflowRule[]; +type Workflows = { [key: string]: [WorkflowRules, string] }; + +function parseInput(filePath: string): Workflows { + const lines = fs.readFileSync(filePath, 'utf-8').split('\n').filter(line => line); + let workflows: Workflows = {}; + let currentWorkflow: string[] = []; + + for (const line of lines) { + if (!line.startsWith('{') && currentWorkflow.length > 0) { + processWorkflow(currentWorkflow); + currentWorkflow = []; + } + currentWorkflow.push(line); + } + if (currentWorkflow.length > 0) { + processWorkflow(currentWorkflow); + } + + function processWorkflow(workflowLines: string[]) { + const [name, rulesStr] = workflowLines[0].split('{'); + const rules = rulesStr.slice(0, -1).split(','); + workflows[name] = [[], rules.pop() as string]; + for (const rule of rules) { + const [condition, target] = rule.split(':'); + const [key, comparison, ...value] = Array.from(condition); + workflows[name][0].push([key, comparison, parseInt(value.join('')), target]); + } + } + + return workflows; +} + +function countRanges(workflows: Workflows, ranges: { [key: string]: Range }, name = 'in'): number { + if (name === 'R') return 0; + if (name === 'A') return Object.values(ranges).reduce((acc, [start, stop]) => acc * (stop - start + 1), 1); + + const [rules, fallback] = workflows[name]; + let total = 0; + + for (const [key, comparison, value, target] of rules) { + const [start, stop] = ranges[key]; + let tRange: Range, fRange: Range; + + if (comparison === '<') { + tRange = [start, value - 1]; + fRange = [value, stop]; + } else { + tRange = [value + 1, stop]; + fRange = [start, value]; + } + + if (tRange[0] <= tRange[1]) { + total += countRanges(workflows, { ...ranges, [key]: tRange }, target); + } + if (fRange[0] <= fRange[1]) { + ranges[key] = fRange; + } else { + break; + } + } + return total + countRanges(workflows, ranges, fallback); +} + +function testAlgorithm(testFile: string, expected: number) { + const workflows = parseInput(testFile); + const result = countRanges(workflows, { 'x': [1, 4000], 'm': [1, 4000], 'a': [1, 4000], 's': [1, 4000] }); + console.assert(result === expected, `Test failed: expected ${expected}, got ${result}`); + console.log('Test passed successfully.'); +} + +function main() { + try { + console.log('Running test...'); + testAlgorithm('../test.txt', 167409079868000); + + console.log('Test passed. Running on actual input...'); + const workflows = parseInput('../input.txt'); + const result = countRanges(workflows, { 'x': [1, 4000], 'm': [1, 4000], 'a': [1, 4000], 's': [1, 4000] }); + console.log(`Result for the puzzle input: ${result}`); + } catch (error) { + console.error(`Error: ${error}`); + process.exit(1); + } +} + +main();