% Usage: swipl part1.pl input.txt :- use_module(library(pio)). :- use_module(library(dcg/basics)). :- initialization(main, main). main([FileName | _]) :- input(FileName, Lines), foldl([Line, Prev, Curr]>>(count_resolutions(Line, N), Curr is Prev + N), Lines, 0, Ns), writef('Res=%w\n', [Ns]). count_resolutions(Line-Bads, N) :- writef('Resolving %w\n', [Line-Bads]), findall(Res, resolve(Line, Bads, Res), Resolutions), length(Resolutions, N). % Bads is list of contiguous blocks of bad items in Xs; w/unks resolved in Ys. resolve([], [], []). resolve([good|Xs], Bads, [good|Ys]) :- resolve(Xs, Bads, Ys). resolve([unk|Xs], Bads, Ys) :- resolve([good|Xs], Bads, Ys); resolve([bad|Xs], Bads, Ys). resolve([bad|Xs], [N|Bads], Ys) :- length(BadsUnks, N), (Next = good; Next = unk), append(BadsUnks, [Next|RemainingXs], [bad|Xs]), bads_or_unks(BadsUnks), resolve([good|RemainingXs], Bads, RemainingYs), nbads(BadRun, N), append(BadRun, RemainingYs, Ys). % List contains all bads or unks bads_or_unks([]). bads_or_unks([bad|List]) :- bads_or_unks(List). bads_or_unks([unk|List]) :- bads_or_unks(List). % List contains exactly N bad items. nbads([], 0). nbads([bad|List], N) :- N > 0, Remain is N - 1, nbads(List, Remain). % read input file into [(good;bad;unk)]-[list of bad runs] input(FileName, Lines) :- phrase_from_file(lines(Lines), FileName). lines([]) --> eos. lines([Status-Parity|Lines]) --> status(Status), parity(Parity), lines(Lines). status([good]) --> " ". status([good|Cdr]) --> ".", status(Cdr). status([bad|Cdr]) --> "#", status(Cdr). status([unk|Cdr]) --> "?", status(Cdr). parity([N]) --> number(N), ("\n"; eos). parity([N|Cdr]) --> number(N), ",", parity(Cdr).