From 506f945d805186e43026b407e6a3a68c4d5cf0ed Mon Sep 17 00:00:00 2001 From: rhiannon morris Date: Sun, 11 Dec 2022 09:00:55 +0100 Subject: [PATCH] day11 --- Makefile | 6 ++- aoc.m | 4 +- basics.m | 16 +++++-- day1.m | 5 +- day11.m | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 day11.m diff --git a/Makefile b/Makefile index 05728b7..d06d253 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ -# this seems to break day7 for some absolutely bizarre reason -MMCFLAGS := # -s asm_fast.par.gc.stseg +MMCFLAGS := \ + --infer-all --warn-unused-imports + # this seems to break day7 for some absolutely bizarre reason + # -s asm_fast.par.gc.stseg all: aoc diff --git a/aoc.m b/aoc.m index cb7a7b4..564d2d6 100644 --- a/aoc.m +++ b/aoc.m @@ -8,8 +8,6 @@ :- import_module basics. :- import_module string. :- import_module list. -:- import_module exception. -:- import_module univ. main(!IO) :- wrap_main(main2, !IO). @@ -48,6 +46,7 @@ run_day(Day, Part, Lines, Out) :- :- import_module day8. :- import_module day9. :- import_module day10. +:- import_module day11. :- pred solution(int::in, sol::out(sol)) is semidet. solution(1, day1.run). @@ -60,3 +59,4 @@ solution(7, day7.run). solution(8, day8.run). solution(9, day9.run). solution(10, day10.run). +solution(11, day11.run). diff --git a/basics.m b/basics.m index ae702da..bf2444a 100644 --- a/basics.m +++ b/basics.m @@ -9,7 +9,9 @@ :- func part(part, T, T) = T. -:- type answer ---> int(int); string(string); lines(list(string)). +:- type answer ---> + int(int); string(string); lines(list(string)); + some [T] other(T). :- pred output(answer::in, io::di, io::uo) is det. @@ -39,10 +41,10 @@ :- type chars == list(char). -:- import_module int. - :- func sum(list(int)) = int. +:- func prod(list(int)) = int. :- func replicate(int, T) = list(T). +:- func rev_sort(list(T)) = list(T). :- func map_index(func(int, T) = U, list(T)) = list(U). @@ -64,6 +66,7 @@ part(two, _, Y) = Y. output(int(I), !IO) :- write_int(I, !IO), nl(!IO). output(string(S), !IO) :- write_string(S, !IO), nl(!IO). output(lines(Ss), !IO) :- write_list(Ss, "\n", write_string, !IO), nl(!IO). +output(other(X), !IO) :- write(X, !IO), nl(!IO). ite(P, T, E) = X :- if P then X = T else X = E. @@ -92,11 +95,18 @@ read_lines_need(File, Lines, !IO) :- need(Res, Lines). +:- import_module int. + sum(Xs) = foldl(plus, Xs, 0). +prod(Xs) = foldl(times, Xs, 1). replicate(N, X) = Out :- if N = 0 then Out = [] else Out = [X | replicate(N - 1, X)]. +:- import_module std_util. + +rev_sort(Xs) = sort(converse(ordering), Xs). + :- func map_index(int, func(int, T) = U, list(T)) = list(U). map_index(_, _, []) = []. map_index(I, F, [X | Xs]) = [F(I, X) | map_index(I+1, F, Xs)]. diff --git a/day1.m b/day1.m index aa10a24..2126737 100644 --- a/day1.m +++ b/day1.m @@ -6,10 +6,7 @@ :- implementation. :- import_module list. -:- import_module std_util. :- import_module maybe. -:- import_module string. -:- import_module int. :- pragma no_determinism_warning(run/3). run(one, Lines, int(det_head(go(Lines)))). @@ -17,7 +14,7 @@ run(two, Lines, int(sum(take_upto(3, go(Lines))))). :- func go(lines) = list(int). go(Lines) = - sort(converse(ordering), map(sum, gather(map(to_int_may, Lines)))). + rev_sort(map(sum, gather(map(to_int_may, Lines)))). :- func gather(list(maybe(T))) = list(list(T)). gather(Xs) = Ys :- gather(Xs, Ys). diff --git a/day11.m b/day11.m new file mode 100644 index 0000000..b2ac9bf --- /dev/null +++ b/day11.m @@ -0,0 +1,141 @@ +:- module day11. +:- 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 item == int. + +:- type op ---> add(int); mul(int); square. +:- type test == int. + +:- type monkey ---> + m(items :: list(item), + op :: op, test :: test, + if_true :: int, if_false :: int, + inspected :: int). +:- func inspected(monkey) = int. +:- func test(monkey) = int. +:- type monkeys == list(monkey). + +:- type divmod ---> dm(d :: int, m :: int). + +:- func op(op, item) = item. +op(add(M), N) = M + N. +op(mul(M), N) = M * N. +op(square, N) = N * N. + +:- func op(op, divmod, item) = item. +op(O, dm(D, M), N) = op(O, N) `div` D `mod` M. + +:- pred test(test::in, item::in) is semidet. +test(M, N) :- N mod M = 0. + + +:- import_module parsing_utils. + +eof(Src) --> not next_char(Src, _). + +:- pred kw(src::in, string::in, ps::in, ps::out) is semidet. +kw(Src, Kw) --> ikeyword("abcdefghijklmnopqrstuvwxyz", Kw, Src, _). + +:- pred kws(src::in, list(string)::in, ps::in, ps::out) is semidet. +kws(_, []) --> []. +kws(Src, [Kw | Kws]) --> kw(Src, Kw), kws(Src, Kws). + +colon(Src) --> punct(":", Src, _). +comma(Src) --> punct(",", Src, _). +equal(Src) --> punct("=", Src, _). +plus(Src) --> punct("+", Src, _). +star(Src) --> punct("*", Src, _). + + +:- pred monkeys(src::in, monkeys::out, ps::in, ps::out) is semidet. +monkeys(Src, Ms) --> one_or_more(monkey, Src, Ms), eof(Src). + +:- pred monkey(src::in, monkey::out, ps::in, ps::out) is semidet. +monkey(Src, m(reverse(I), O, P, T, F, 0)) --> + kw(Src, "monkey"), int_literal_as_string(Src, _), colon(Src), + kws(Src, ["starting", "items"]), colon(Src), items(Src, I), + kw(Src, "operation"), colon(Src), + kw(Src, "new"), equal(Src), op(Src, O), + kw(Src, "test"), colon(Src), test(Src, P), + kws(Src, ["if", "true"]), colon(Src), act(Src, T), + kws(Src, ["if", "false"]), colon(Src), act(Src, F). + +:- pred items(src::in, list(item)::out, ps::in, ps::out) is semidet. +items(Src, Is) --> comma_separated_list(int_literal, Src, Is). + +:- pred op(src::in, op::out, ps::in, ps::out) is semidet. +op(Src, Op) --> + kw(Src, "old"), + (if star(Src) then + (if int_literal(Src, N) then {Op = mul(N)} + else kw(Src, "old"), {Op = square}) + else plus(Src), int_literal(Src, N), {Op = add(N)}). + +:- pred test(src::in, test::out, ps::in, ps::out) is semidet. +test(Src, N) --> kws(Src, ["divisible", "by"]), int_literal(Src, N). + +:- pred act(src::in, int::out, ps::in, ps::out) is semidet. +act(Src, N) --> kws(Src, ["throw", "to", "monkey"]), int_literal(Src, N). + + +:- pred give(item::in, int::in, monkeys::in, monkeys::out) is det. +give(_, _, [], _) :- die("list too short"). +give(I, N, [!.M | !.Ms], [!:M | !:Ms]) :- + if N = 0 then !M^items := [I | !.M^items] + else give(I, N - 1, !Ms). + +:- pred get(int::in, monkey::out, monkeys::in, monkeys::out) is semidet. +get(N, X, [!.M | !.Ms], [!:M | !:Ms]) :- + if N = 0 then + X = !.M, + !M^inspected := !.M^inspected + length(!.M^items), + !M^items := [] + else + get(N - 1, X, !Ms). + +:- pred step(divmod::in, monkey::in, int::in, monkeys::in, monkeys::out) is det. +step(DM, M, I, !Ms) :- + I2 = op(M^op, DM, I), + (if test(M^test, I2) then + give(I2, M^if_true, !Ms) + else + give(I2, M^if_false, !Ms)). + +:- pred turn(divmod::in, int::in, monkeys::in, monkeys::out) is semidet. +turn(DM, I, !Ms) :- + get(I, M, !Ms), + foldr(step(DM, M), M^items, !Ms). + +:- pred round(divmod::in, int::in, monkeys::in, monkeys::out) is det. +round(DM, I, !Ms) :- + if turn(DM, I, !Ms) then round(DM, I + 1, !Ms) else true. + +:- pred round(divmod::in, monkeys::in, monkeys::out) is det. +round(DM, !Ms) :- round(DM, 0, !Ms). + +:- pred rounds(divmod::in, int::in, monkeys::in, monkeys::out) is det. +rounds(DM, N, !Ms) :- + if N = 0 then true else + round(DM, !Ms), + rounds(DM, N - 1, !Ms). + +:- pred rounds(part::in, monkeys::in, monkeys::out) is det. +rounds(Part, !Ms) :- + DM = dm(part(Part, 3, 1), prod(map(test, !.Ms))), + rounds(DM, part(Part, 20, 10_000), !Ms). + +run(Part, Lines, Out) :- + parse(join_list("\n", Lines), one_or_more(monkey), Res), + (if Res = ok(Monkeys) then + rounds(Part, Monkeys, Final), + Out = int(prod(take_upto(2, rev_sort(map(inspected, Final))))) + else + Out = 'new other'(Res)).