% Usage: swipl part2.pl input.txt :- use_module(library(pio)). :- use_module(library(dcg/basics)). :- initialization(main, main). test :- main(['test.txt']). main([FileName | _]) :- input(FileName, Lines), concurrent_maplist(resolve_repeated, Lines, Ns), sum_list(Ns, Count), writef('Res=%w\n', [Count]). resolve_repeated(Line-Bads, N) :- append([Line, [?], Line, [?], Line, [?], Line, [?], Line], L5), append([Bads, Bads, Bads, Bads, Bads], B5), abolish_private_tables, table(resolve/2), resolve(L5-B5, N). % Bads is list of contiguous blocks of bad items in Xs; w/unks resolved in Y. resolve([]-[], 1). resolve([o|Xs]-Bads, Y) :- resolve(Xs-Bads, Y). resolve([?|Xs]-Bads, Y) :- findall(N, (resolve([o|Xs]-Bads, N); resolve([#|Xs]-Bads, N)), Ys), sum_list(Ys, Y). resolve([#|Xs]-[N|Bads], Y) :- length(BadsUnks, N), ( append(BadsUnks, [], [#|Xs]), RemainingXs = [] ; append(BadsUnks, [Next|RemainingXs], [#|Xs]), (Next = o; Next = ?) ), bads_or_unks(BadsUnks), resolve(RemainingXs-Bads, Y). % List contains all bads or unks bads_or_unks([]). bads_or_unks([#|List]) :- bads_or_unks(List). bads_or_unks([?|List]) :- bads_or_unks(List). % List contains exactly N bad items. nbads([], 0). nbads([#|List], N) :- N > 0, Remain is N - 1, nbads(List, Remain). processed_line(1, Line-Bads, NewLine-NewBads) :- append(Line, [o], NewLine), NewBads = Bads. % read input file into [(o;#;?)]-[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([]) --> " ". status([o]) --> all_dots, " ". status([o, #|Cdr]) --> all_dots, "#", status(Cdr). status([o, ?|Cdr]) --> all_dots, "?", status(Cdr). status([#|Cdr]) --> "#", status(Cdr). status([?|Cdr]) --> "?", status(Cdr). all_dots --> ".". all_dots --> ".", all_dots. parity([N]) --> number(N), ("\n"; eos). parity([N|Cdr]) --> number(N), ",", parity(Cdr).