import { join } from 'https://deno.land/std@0.167.0/path/mod.ts'; type Directory = { type: 'directory' }; type File = { type: 'file'; size: number }; type Tree = Record>; function buildTree(shellLog: string): Tree { const tree: Tree = {}; let curPath = ''; for (const line of shellLog.split('\n')) { if (line.startsWith('$')) { if (line === '$ ls') { continue; } curPath = join(curPath, line.split(' ').at(-1)!); tree[curPath] ??= {}; continue; } if (line.startsWith('dir')) { const dirName = line.split(' ').at(-1)!; tree[curPath][dirName] = { type: 'directory', }; continue; } // only option left is file const [fileSize, fileName] = line.split(' ') as [string, string]; tree[curPath][fileName] = { type: 'file', size: parseInt(fileSize), }; } return tree; } function duRec(tree: Tree, entryPath = '/'): Record { let result: Record = {}; let curSize = 0; for (const [name, entry] of Object.entries(tree[entryPath as keyof typeof tree])) { if (entry.type === 'directory') { const newEntry = join(entryPath, name); result = Object.assign(result, duRec(tree, newEntry)) as Record; curSize += result[newEntry]; } else curSize += entry.size; } result[entryPath] = curSize; return result; } const input = Deno.readTextFileSync('./input.txt').trimEnd(); const tree = buildTree(input); const dirSizes = Object.values(duRec(tree)); const p1 = dirSizes.filter((size) => (size <= 100000)) .reduce((prev, cur) => prev + cur, 0); console.log('Solution Part 1:', p1); dirSizes.sort((a, b) => a - b); const free = 70000000 - dirSizes.at(-1)!; const p2 = dirSizes.find((size) => (free + size) >= 30000000); console.log('Solution Part 2:', p2);