:- use_module(library(dcg/basics)). direction(left) --> "L". direction(right) --> "R". directions([]) --> []. directions([D|Ds]) --> direction(D), directions(Ds). label(L) --> alpha_to_lower(A), alpha_to_lower(B), alpha_to_lower(C), {atom_codes(L, [A,B,C])}. line(A-B-C) --> label(A), blanks, "=", blanks, "(", label(B), ",", blanks, label(C), ")". lines([]) --> blanks. lines([L|Ls]) --> line(L), blanks, lines(Ls). file(Ds, Ls) --> directions(Ds), blanks, lines(Ls). set_map(Map) :- reset_map, maplist(assert_map1, Map). reset_map :- abolish(left/2), abolish(right/2). assert_map1(A-B-C) :- assertz(left(A, B)), assertz(right(A, C)). :- dynamic left/2, right/2. loop_with(P, N, N, _, _, Z) :- call(P, Z), !. loop_with(P, N, I, [D|Ds], All, Here) :- call(D, Here, Next), I1 is I + 1, loop_with(P, N, I1, Ds, All, Next). loop_with(P, N, I, [], All, Here) :- loop_with(P, N, I, All, All, Here). go(N, Ds) :- loop_with(=(zzz), N, 0, Ds, Ds, aaa). part1(File) :- phrase_from_file(file(Ds, Map), File), set_map(Map), go(N, Ds), writeln(N). is_start(S) :- atom_chars(S, [_, _, a]). is_final(S) :- atom_chars(S, [_, _, z]). starts(Xs) :- setof(X, Y^(left(X, Y), is_start(X)), Xs). loop_multi(Ds, Here, N) :- loop_with(is_final, N, 0, Ds, Ds, Here). go_multi(Ns, Ds) :- starts(Ss), maplist(loop_multi(Ds), Ss, Ns). lcm(M, N, L) :- L is lcm(M, N). part2(File) :- phrase_from_file(file(Ds, Map), File), set_map(Map), go_multi(Ns, Ds), foldl(lcm, Ns, 1, N), writeln(N). % vim: set ft=prolog :