aoc/2024/09/bad.solution.nix

123 lines
3.2 KiB
Nix

{lib, ...}: input: let
inherit (builtins) length foldl' filter tail head genList elemAt;
inherit (lib) stringToCharacters toInt mod last reverseList min;
data = input
|> lib.trim
|> stringToCharacters
|> map toInt;
disk = data
|> foldl' (acc: size:
let
index = length acc;
id = index / 2;
prev = last acc;
in
acc ++ [{
inherit size;
id = if index == 0 || mod index 2 == 0 then id else null;
start = if length acc == 0 then 0 else prev.start + prev.size;
}]
) []
;
# works, but max-call-depth exceeded on real input... ugh
defragRec = {free, files}: if free == [] then files else
let
file = last files;
space = head free;
size = min (space.size) (file.size);
in
if file.start + file.size < space.start then files else
defragRec {
files = (if size == 0 then [] else [{
inherit (file) id;
inherit (space) start;
inherit size;
}])
++ (lib.sublist 0 (length files - 1) files)
++ (if file.size == size then [] else [{
inherit (file) id start;
size = file.size - size;
}]);
free = (if size == 0 then [] else [{
start = space.start + size;
size = space.size - size;
}])
++ tail free;
}
;
defrag = free: file:
free |> foldl' (acc: space: let
amt = min acc.rem space.size;
in if (isNull space.id || space.id == file.id) -> acc.rem == 0
then acc // {free = acc.free ++ [space];}
else {
file = acc.file ++ [{
inherit (file) id;
inherit (space) start;
size = amt;
}];
free = acc.free ++ (if space.size - amt == 0 then [] else [{
id = space.id;
start = space.start + amt;
size = space.size - amt;
}]);
rem = acc.rem - amt;
})
{free = []; file = []; rem = file.size;}
|> (result: { inherit (result) free file; })
;
defragged = let
files = disk
|> filter ({id, ...}: !isNull id)
|> reverseList
;
in files |> foldl' (acc: file: let
res = builtins.trace "defraging with file ${toString file.id}" (defrag acc.free file);
in
{
inherit (res) free;
files = acc.files ++ res.file;
})
{free = disk; files = [];}
;
checksum = disk: disk.files
|> foldl' (acc: {id, size, start}: acc + (id * size * (start + ((size - 1) / 2.0)))) 0
;
fullDisk = disk |> map (sect: genList (i: sect.id) sect.size) |> lib.concatLists;
defragFullDisk = d: let
notEmptyDisk = d |> filter (s: !isNull s);
in d |> foldl' ({i, j, acc}: id: let
idFromEnd = elemAt notEmptyDisk i;
in {
acc = acc ++ [(if j >= length notEmptyDisk then null else if isNull id then idFromEnd else id)];
i = if isNull id then i + 1 else i;
j = j + 1;
}
) {i = 0; acc = []; j = 0;};
checksumFullDisk = d: d |> filter (s: !isNull s)
|> foldl'
({i, total}: id: {i = i + 1; total = total + i * id;})
{i = 0; total = 0;};
in {
inherit data disk defrag defragged checksum fullDisk;
part1result = defragged |> checksum;
# defraggedFullDisk = defragFullDisk fullDisk;
# part1result = (defragFullDisk fullDisk).acc |> checksumFullDisk;
}