AoC-2022-Nix/days/7/solution.nix
zuckerberg 260263b472 Day 7
2022-12-07 22:54:13 -07:00

60 lines
2.0 KiB
Nix

with import ../../util.nix;
let
# read input
cmdOuts = splitString "\n$ " (removePrefix "$ " (readFile ./input));
fileTree =
let
start = { cwd = []; tree = {}; };
applyCmd = acc: cmdOut:
let
# parse cmd + cmd output
lines = splitString "\n" cmdOut;
cmd = splitString " " (head lines);
out = tail lines;
# apply cmds
applyCd = cwd: param:
if param == ".." then dropLast cwd
else if param == "/" then []
else cwd ++ [param];
applyLs = cwd: param:
let
parseFileDir = splitLine:
if head splitLine == "dir" then { ${last splitLine} = {}; }
else { ${last splitLine} = toInt (head splitLine); };
makeSubTree = combineAttrs (map (line: parseFileDir (splitString " " line)) param);
in
setAttrByPath cwd makeSubTree;
in
if head cmd == "cd" then
{ inherit (acc) tree; cwd = applyCd acc.cwd (last cmd); }
else # ls
{ inherit (acc) cwd; tree = recursiveUpdate acc.tree (applyLs acc.cwd out); };
in (foldl applyCmd start cmdOuts).tree;
sizeOfDir = dir:
sum (map (v: if isAttrs v then sizeOfDir v else v) (attrValues dir));
# a flat list of sizes for all directories
dirSizes = recurisveVisitAttrs (n: v: if isAttrs v then sizeOfDir v else 0) fileTree;
# a list of sizes for small directories
smallDirSizes =
foldl (acc: size: if size < 100000 && size != 0 then acc ++ [size] else acc) [] dirSizes;
totalUsedSize = sizeOfDir fileTree;
# smallest directory to delete to free target size
minDirOfAtLeastSize = targetSize: foldl (acc: s: if s >= targetSize && s < acc then s else acc) totalUsedSize dirSizes;
totalFsSize = 70000000;
fsSizeNeeded = 30000000;
availableSpace = totalFsSize - totalUsedSize;
spaceNeeded = fsSizeNeeded - availableSpace;
in rec {
part1 = sum smallDirSizes;
part2 = minDirOfAtLeastSize spaceNeeded;
}