:- use_module(library(dcg/basics)). many(_, []) --> []. many(P, [X|Xs]) --> call(P, X), many(P, Xs). seed_list(Seeds) --> "seeds:", blanks, numbers(Seeds). blank_sep(_, []) --> []. blank_sep(P, [X|Xs]) --> call(P, X), blanks, blank_sep(P, Xs). numbers(Ns) --> blank_sep(number, Ns). name(X) --> many(alpha_to_lower, Cs), {atom_codes(X, Cs)}. header(From, To) --> name(From), "-to-", name(To), blanks, "map:". map_line(m(Src, Dest, Len)) --> numbers([Dest, Src, Len]). part(p(From, To, Elems)) --> header(From, To), blanks, blank_sep(map_line, Elems), blanks. file1(Seeds, Parts) --> seed_list(Seeds), blanks, many(part, Parts). parse1(Seeds, Parts, File) :- once(phrase_from_file(file1(Seeds, Parts), File)). :- dynamic seed/1, entry/5, next_step/2. setup1(Seeds, Parts) :- transaction((retractall(seed(_)), retractall(entry(_, _, _, _, _)), retractall(next_step(_, _)), setup_seeds1(Seeds), setup_map(Parts))). setup_seeds1(Seeds) :- maplist(assert_seed1, Seeds). assert_seed1(S) :- assertz(seed(S)). setup_map(Parts) :- maplist(setup_part, Parts). setup_part(p(From, To, Elems)) :- assertz(next_step(From, To)), maplist(assert_entry(From, To), Elems). assert_entry(From, To, m(Src, Dest, Len)) :- assert(entry(From, To, Src, Dest, Len)). parse_setup1(File) :- parse1(Seeds, Parts, File), setup1(Seeds, Parts). map1(From, To, Src, Dest) :- entry(From, To, Src0, Dest0, Len), Src1 is Src0 + Len, Src >= Src0, Src < Src1, !, Index is Src - Src0, Dest is Dest0 + Index. map1(From, To, Src, Src) :- next_step(From, To). map1N(From, From, Src, Src) :- !. map1N(From, To, Src, Dest) :- map1(From, Mid, Src, MidN), map1N(Mid, To, MidN, Dest). part1(File) :- parse_setup1(File), setof(L, S^(seed(S), map1N(seed, location, S, L)), [L|_]), writeln(L). seed_ranges(Seeds) --> "seeds:", blanks, blank_sep(seed_range, Seeds). seed_range(s(Lo, Len)) --> numbers([Lo, Len]). file2(Seeds, Parts) --> seed_ranges(Seeds), blanks, many(part, Parts). parse2(Seeds, Parts, File) :- once(phrase_from_file(file2(Seeds, Parts), File)). min_range(To, Lo, Hi) :- setof(r(Dest, Len), From^Src^entry(From, To, Src, Dest, Len), [r(Lo0, Len)|_]), Hi0 is Lo0 + Len, Hi1 is Lo0 - 1, (Lo = Lo0, Hi = Hi0 ; Lo = 0, Hi = Hi1). range_size(s(_, Len), Len). seed_count(Seeds, N) :- maplist(range_size, Seeds, Sizes), foldl(plus, Sizes, 0, N). % vim: set ft=prolog :