56 lines
1.6 KiB
Mathematica
56 lines
1.6 KiB
Mathematica
:- module day7.
|
|
:- interface.
|
|
:- import_module basics.
|
|
|
|
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
|
|
|
:- implementation.
|
|
:- import_module int.
|
|
:- import_module string.
|
|
:- import_module list.
|
|
|
|
:- type dir ---> dir(size :: int, dirs :: dirs).
|
|
:- func size(dir) = int.
|
|
:- type dirs == list(dir).
|
|
|
|
:- pred dir(dir::out, lines::in, lines::out) is nondet.
|
|
dir(dir(Size, Dirs)) -->
|
|
[Cd], {append("$ cd ", _, Cd)},
|
|
["$ ls"],
|
|
files(Files),
|
|
dirs(Dirs),
|
|
{Size = Files + sum(map(size, Dirs))},
|
|
(["$ cd .."] ; []).
|
|
|
|
:- pred files(int::out, lines::in, lines::out) is multi.
|
|
files(Size + Rest) -->
|
|
[Line], {to_int(head(words(Line)), Size)},
|
|
files(Rest).
|
|
files(Size) -->
|
|
[Dir], {append("dir ", _, Dir)},
|
|
files(Size).
|
|
files(0) --> [].
|
|
|
|
:- pred dirs(dirs::out, lines::in, lines::out) is multi.
|
|
dirs([D | Ds]) --> dir(D), dirs(Ds).
|
|
dirs([]) --> [].
|
|
|
|
:- pred find(pred(dir)::(pred(in) is semidet), dir::in, list(dir)::out) is det.
|
|
find(P, Dir, Out) :-
|
|
map(find(P), dirs(Dir), Outs), Children = condense(Outs),
|
|
(if P(Dir) then Out = [Dir | Children] else Out = Children).
|
|
|
|
:- pred size_lte(int::in, dir::in) is semidet.
|
|
size_lte(Size, Dir) :- size(Dir) =< Size.
|
|
|
|
:- pred size_gte(int::in, dir::in) is semidet.
|
|
size_gte(Size, Dir) :- size(Dir) >= Size.
|
|
|
|
:- pred go(part::in, dir::in, int::out) is det.
|
|
go(one, Top, sum(map(size, Found))) :-
|
|
find(size_lte(100_000), Top, Found).
|
|
go(two, Top, det_head(sort(map(size, Found)))) :-
|
|
find(size_gte(size(Top) - 40_000_000), Top, Found).
|
|
|
|
run(Part, Lines, int(Out)) :-
|
|
if dir(Top, Lines, []) then go(Part, Top, Out) else die("bad input").
|