:- 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").