diff options
Diffstat (limited to 'day-7/index.ts')
-rw-r--r-- | day-7/index.ts | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/day-7/index.ts b/day-7/index.ts new file mode 100644 index 0000000..689e647 --- /dev/null +++ b/day-7/index.ts @@ -0,0 +1,126 @@ +import fs from "fs"; + +const file = fs.readFileSync("./input.txt").toString(); + +const lines = file.split("\n").filter((x) => x.length); + +// File or Directory +interface Item { + type: "dir" | "file"; + name: string; + size: number; +} + +interface CommandWithOutput { + command: string; + outputs: Item[]; +} + +interface CommandWithDir extends CommandWithOutput { + directory: string[]; +} + +function isCommandString(s: string) { + return s.startsWith("$"); +} + +function parseLines(lines: string[]): CommandWithOutput[] { + return lines.reduce((acc, current, index) => { + if (isCommandString(current)) { + const nextCommandIndex = + lines.slice(index + 1).findIndex(isCommandString) + index + 1; + + const smartIndex = + nextCommandIndex === index ? lines.length : nextCommandIndex; + const outputs = lines.slice(index + 1, smartIndex).map((line) => { + const dirMatch = line.match(/dir (.*)/); + const fileMatch = line.match(/(.*) (.*)/); + + if (dirMatch && dirMatch[1]) + return { + type: "dir", + size: 0, + name: dirMatch[1], + } satisfies Item; + if (fileMatch) + return { + type: "file", + size: Number(fileMatch[1]), + name: fileMatch[2], + } satisfies Item; + throw new Error("Unhandled"); + }); + acc.push({ outputs, command: current }); + } + return acc; + }, [] as CommandWithOutput[]); +} + +function computeDirectories(commands: CommandWithOutput[]): CommandWithDir[] { + return commands.reduce((acc, current) => { + const previousDir = acc[acc.length - 1]?.directory; + + const match = current.command.match(/\$ cd (.*)/); + const directory = match + ? previousDir + ? match[1] !== ".." + ? [...previousDir, match[1]] + : [...previousDir.slice(0, -1)] + : [match[1]] + : [...previousDir]; + + acc.push({ ...current, directory }); + return acc; + }, [] as CommandWithDir[]); +} + +const parsed = parseLines(lines); +const withDirs = computeDirectories(parsed); +const lsOutputs = withDirs.filter((cmd) => cmd.command === "$ ls"); + +// DIRTY CODE STARTS HERE +function computeDirSize( + cmd: CommandWithDir & { totalSize: number | undefined }, +) { + if (cmd.totalSize !== undefined) return; + cmd.outputs + .filter((f) => f.type === "dir") + .forEach((dir) => { + const path = [...cmd.directory, dir.name]; + const dirNode = data.find( + (datum) => JSON.stringify(datum.directory) === JSON.stringify(path), + ); + + if (!dirNode) throw new Error(`Unknown size ${dir.name}`); + if (dirNode.totalSize === undefined) { + computeDirSize(dirNode); + } + if (dirNode.totalSize !== undefined) { + dir.size = dirNode.totalSize; + } else { + throw new Error( + `${dir.name}, ${JSON.stringify(path)}, ${JSON.stringify(dirNode)}`, + ); + } + }); + + const totalSize = cmd.outputs.reduce((sum, f) => sum + f.size, 0); + + cmd.totalSize = totalSize; + // console.log("Setting size ", totalSize, " to dir", cmd.directory); +} + +const data = lsOutputs.map((o) => ({ + ...o, + totalSize: undefined as undefined | number, +})); + +data.forEach(computeDirSize); +console.log(data); + +const sum = data + .filter((d) => d.totalSize) + .filter((datum) => (datum?.totalSize || 0) <= 100_000) + .reduce((acc, d) => acc + (d?.totalSize || 0), 0); + +console.log(sum); |