aoc2022/day10.m

67 lines
1.7 KiB
Mathematica

:- module day10.
:- 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.
:- import_module char.
:- type instr ---> noop; addx(int).
:- pred line(instr::out, list(string)::in, list(string)::out) is semidet.
line(noop) --> ["noop"].
line(addx(N)) --> ["addx", X], {to_int(X, N)}.
:- pred line(string::in, instr::out) is semidet.
line(Str, I) :- line(I, words(Str), []).
:- type reg == int.
:- type cycle == int.
:- type signal == int.
:- pred regs(reg::in, list(instr)::in, list(reg)::out) is det.
regs(_, [], []).
regs(R, [noop | Is], [R | Ss]) :-
regs(R, Is, Ss).
regs(R, [addx(N) | Is], [R, R | Ss]) :-
regs(R + N, Is, Ss).
:- pred regs(lines::in, list(signal)::out) is semidet.
regs(Lines, Signals) :-
map(line, Lines, Instrs),
regs(1, Instrs, Signals).
:- func signals(cycle, list(reg)) = list(reg).
signals(_, []) = [].
signals(C, [R | Rs]) = [C * R | signals(C + 1, Rs)].
:- func signals(list(reg)) = list(reg).
signals(Rs) = signals(1, Rs).
:- func render1(cycle, list(reg)) = list(char).
render1(_, []) = [].
render1(C, [R | Rs]) = [X | Xs] :-
(if abs(R - C) =< 1 then X = '' else X = ' '),
Xs = render1((C + 1) mod 40, Rs).
:- func render(list(reg)) = lines.
render(Rs) = map(from_char_list, chunk(render1(0, Rs), 40)).
:- pragma no_determinism_warning(run/3).
run(Part, Lines, Out) :-
if regs(Lines, Regs)
then
( Part = one,
Indices = [20, 60, 100, 140, 180, 220],
Out = int(sum(map(det_index1(signals(Regs)), Indices)))
; Part = two,
Out = lines(render(Regs))
)
else die("bad input").