import { Coll, Collection } from "util/collection";
// If blank strings/ints is not enough
export const inputMapper = (inputs: string) => inputs;
interface Dir {
name: string;
content: Collection<Dir | File>;
}
interface File {
name: string;
size: number;
}
function buildFileTree(inputs: Collection<string>): Dir {
const dirs: Dir = { name: "/", content: Coll() };
const cmds = inputs.slice(1);
let currentDir = dirs;
const parentDirs: Collection<Dir> = Coll();
for (let i = 0; i < cmds.length; i++) {
if (cmds[i].startsWith("$ cd")) {
const dirName = cmds[i].split(" ")[2];
if (dirName === "..") {
currentDir = parentDirs.pop()!;
} else {
const dir = currentDir.content.find((d) => d.name === dirName) as Dir;
parentDirs.push(currentDir);
currentDir = dir;
}
}
if (cmds[i].startsWith("$ ls")) {
const content = Coll<Dir | File>();
// Lets hope there are no empty dirs..
for (let j = 1; i + j < cmds.length; j++) {
const [a, b] = cmds[i + j].split(" ");
if (a.match(/^[0-9]/)) {
content.push({ name: b, size: parseInt(a) });
} else if (a === "dir") {
content.push({ name: b, content: Coll() });
} else {
i += j - 1;
break;
}
}
currentDir.content.push(...content);
}
}
return dirs;
}
function isFile(dir: Dir | File): dir is File {
return (dir as File).size !== undefined;
}
function getDirSize(dir: Dir): number {
return dir.content.reduce((acc, c) => {
if (isFile(c)) {
return acc + c.size;
} else {
return acc + getDirSize(c as Dir);
}
}, 0);
}
const maxDirSize = 100_000 as const;
function getDirsBelowLimit(dir: Dir): Collection<Dir> {
const dirs = Coll<Dir>();
if (getDirSize(dir) < maxDirSize) {
dirs.push(dir);
}
for (const d of dir.content) {
if (isFile(d)) {
continue;
}
dirs.push(...getDirsBelowLimit(d));
}
return dirs;
}
export function solution1(inputs: Collection<string>): number {
const dirs = buildFileTree(inputs);
return getDirsBelowLimit(dirs).map(getDirSize).x.sum();
}
const availableSpace = 70_000_000 as const;
const requiredSpace = 30_000_000 as const;
function getAllDirs(dir: Dir): Collection<Dir> {
const dirs = Coll<Dir>();
dirs.push(dir);
for (const d of dir.content) {
if (isFile(d)) {
continue;
}
dirs.push(...getAllDirs(d));
}
return dirs;
}
export function solution2(inputs: Collection<string>): number {
const dirs = buildFileTree(inputs);
const leftoverSpace = availableSpace - getDirSize(dirs);
const minimumSpace = requiredSpace - leftoverSpace;
const allDirs = getAllDirs(dirs).map(getDirSize).filter((s) =>
s >= minimumSpace
).x.sortAsc();
return allDirs[0];
}