solve Day08 in JS/TS
This commit is contained in:
parent
dc4dd65452
commit
2ae2c2ba0f
82
Day08/js/solution.js
Normal file
82
Day08/js/solution.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function gcd(a, b) {
|
||||||
|
while (b !== 0) {
|
||||||
|
let t = b;
|
||||||
|
b = a % b;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lcm(a, b) {
|
||||||
|
return (a * b) / gcd(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFile(filePath) {
|
||||||
|
console.log(`Parsing file: ${filePath}`);
|
||||||
|
const data = fs.readFileSync(filePath, 'utf8').trim();
|
||||||
|
const [stepsSection, rulesSection] = data.split('\n\n');
|
||||||
|
const steps = stepsSection.split('').map(char => char === 'L' ? 0 : 1);
|
||||||
|
const rules = rulesSection.split('\n').reduce((acc, line) => {
|
||||||
|
const [state, directions] = line.split('=').map(s => s.trim());
|
||||||
|
const [left, right] = directions.split(',').map(s => s.trim());
|
||||||
|
acc['L'][state] = left.slice(1);
|
||||||
|
acc['R'][state] = right.slice(0, -1);
|
||||||
|
return acc;
|
||||||
|
}, { 'L': {}, 'R': {} });
|
||||||
|
|
||||||
|
return { steps, rules };
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateNetworkSimultaneously(steps, rules) {
|
||||||
|
console.log("Starting navigation of network.");
|
||||||
|
const startNodes = Object.keys(rules['L']).filter(node => node.endsWith('A'));
|
||||||
|
let currentNodes = startNodes;
|
||||||
|
let stepCount = 0;
|
||||||
|
const timeToZ = {};
|
||||||
|
|
||||||
|
while (Object.keys(timeToZ).length < startNodes.length) {
|
||||||
|
currentNodes.forEach((node, index) => {
|
||||||
|
const direction = steps[stepCount % steps.length] === 0 ? 'L' : 'R';
|
||||||
|
const nextNode = rules[direction][node];
|
||||||
|
currentNodes[index] = nextNode;
|
||||||
|
if (nextNode.endsWith('Z') && !(index in timeToZ)) {
|
||||||
|
timeToZ[index] = stepCount + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stepCount++;
|
||||||
|
console.log(`Step ${stepCount}: Current nodes - ${currentNodes}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.values(timeToZ).reduce((acc, val) => lcm(acc, val), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
console.log("Running test...");
|
||||||
|
const testPath = path.join(__dirname, '../test.txt');
|
||||||
|
const { steps, rules } = parseFile(testPath);
|
||||||
|
const expected = 6;
|
||||||
|
const result = navigateNetworkSimultaneously(steps, rules);
|
||||||
|
|
||||||
|
if (result !== expected) {
|
||||||
|
throw new Error(`Test failed: expected ${expected}, got ${result}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Test passed with ${result} steps.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
try {
|
||||||
|
runTest();
|
||||||
|
const inputPath = path.join(__dirname, '../input.txt');
|
||||||
|
const { steps, rules } = parseFile(inputPath);
|
||||||
|
const result = navigateNetworkSimultaneously(steps, rules);
|
||||||
|
console.log(`All paths reached 'Z' nodes simultaneously in ${result} steps.`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
82
Day08/ts/solution.ts
Normal file
82
Day08/ts/solution.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
function gcd(a: number, b: number): number {
|
||||||
|
while (b !== 0) {
|
||||||
|
let t = b;
|
||||||
|
b = a % b;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lcm(a: number, b: number): number {
|
||||||
|
return (a * b) / gcd(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFile(filePath: string): { steps: number[], rules: { [key: string]: { [key: string]: string } } } {
|
||||||
|
console.log(`Parsing file: ${filePath}`);
|
||||||
|
const data = fs.readFileSync(filePath, 'utf8').trim();
|
||||||
|
const [stepsSection, rulesSection] = data.split('\n\n');
|
||||||
|
const steps = stepsSection.split('').map((char: string) => char === 'L' ? 0 : 1);
|
||||||
|
const rules = rulesSection.split('\n').reduce((acc: { [key: string]: { [key: string]: string } }, line: string) => {
|
||||||
|
const [state, directions] = line.split('=').map((s: string) => s.trim());
|
||||||
|
const [left, right] = directions.split(',').map((s: string) => s.trim());
|
||||||
|
acc['L'][state] = left.slice(1);
|
||||||
|
acc['R'][state] = right.slice(0, -1);
|
||||||
|
return acc;
|
||||||
|
}, { 'L': {}, 'R': {} });
|
||||||
|
|
||||||
|
return { steps, rules };
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateNetworkSimultaneously(steps: number[], rules: { [key: string]: { [key: string]: string } }): number {
|
||||||
|
console.log("Starting navigation of network.");
|
||||||
|
const startNodes = Object.keys(rules['L']).filter((node: string) => node.endsWith('A'));
|
||||||
|
let currentNodes = startNodes;
|
||||||
|
let stepCount = 0;
|
||||||
|
const timeToZ: { [key: number]: number } = {};
|
||||||
|
|
||||||
|
while (Object.keys(timeToZ).length < startNodes.length) {
|
||||||
|
currentNodes.forEach((node: string, index: number) => {
|
||||||
|
const direction = steps[stepCount % steps.length] === 0 ? 'L' : 'R';
|
||||||
|
const nextNode = rules[direction][node];
|
||||||
|
currentNodes[index] = nextNode;
|
||||||
|
if (nextNode.endsWith('Z') && !(index in timeToZ)) {
|
||||||
|
timeToZ[index] = stepCount + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stepCount++;
|
||||||
|
console.log(`Step ${stepCount}: Current nodes - ${currentNodes}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.values(timeToZ).reduce((acc: number, val: number) => lcm(acc, val), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest(): void {
|
||||||
|
console.log("Running test...");
|
||||||
|
const testPath = path.join(__dirname, '../test.txt');
|
||||||
|
const { steps, rules } = parseFile(testPath);
|
||||||
|
const expected = 6;
|
||||||
|
const result = navigateNetworkSimultaneously(steps, rules);
|
||||||
|
|
||||||
|
if (result !== expected) {
|
||||||
|
throw new Error(`Test failed: expected ${expected}, got ${result}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Test passed with ${result} steps.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(): void {
|
||||||
|
try {
|
||||||
|
runTest();
|
||||||
|
const inputPath = path.join(__dirname, '../input.txt');
|
||||||
|
const { steps, rules } = parseFile(inputPath);
|
||||||
|
const result = navigateNetworkSimultaneously(steps, rules);
|
||||||
|
console.log(`All paths reached 'Z' nodes simultaneously in ${result} steps.`);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`Error: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": "^20.10.4",
|
||||||
"fs": "^0.0.1-security"
|
"fs": "^0.0.1-security"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -156,6 +157,14 @@
|
|||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.10.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz",
|
||||||
|
"integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.5.6",
|
"version": "7.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
|
||||||
@ -1519,6 +1528,11 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||||
|
},
|
||||||
"node_modules/uri-js": {
|
"node_modules/uri-js": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"eslint": "^8.55.0"
|
"eslint": "^8.55.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": "^20.10.4",
|
||||||
"fs": "^0.0.1-security"
|
"fs": "^0.0.1-security"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "ES2023",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true
|
||||||
|
Loading…
Reference in New Issue
Block a user