109 lines
4.1 KiB
Perl
109 lines
4.1 KiB
Perl
|
answer(Answer) :-
|
||
|
combine([seed_to_soil, soil_to_fertilizer, fertilizer_to_water,
|
||
|
water_to_light, light_to_temperature, temperature_to_humidity,
|
||
|
humidity_to_location], Map),
|
||
|
seed_map(Seeds),
|
||
|
fold_down(Seeds, Map, MappedSeeds),
|
||
|
sort(MappedSeeds, [[Answer, _, _] | _]).
|
||
|
|
||
|
% combine all map predicates into one map
|
||
|
combine([MapPredicate], Map) :-
|
||
|
G =.. [MapPredicate, Map], G.
|
||
|
combine([Map1Predicate, Map2Predicate| RestOfMaps], CombinedMap) :-
|
||
|
G =.. [Map1Predicate, Map1], G,
|
||
|
H =.. [Map2Predicate, Map2], H,
|
||
|
process_map(Map1, ProcessedMap1),
|
||
|
process_map(Map2, ProcessedMap2),
|
||
|
fold_down(ProcessedMap1, ProcessedMap2, Map12),
|
||
|
retractall(map12pred(_)), assertz(map12pred(Map12)),
|
||
|
combine([map12pred | RestOfMaps], CombinedMap).
|
||
|
|
||
|
% combine 2 maps into one
|
||
|
fold_down([], _, []).
|
||
|
fold_down([Pair1 | RestOfMap1], Map2, FoldedMap) :-
|
||
|
split_pair(Pair1, Map2, NewPair1s),
|
||
|
fold_down(RestOfMap1, Map2, RestOfFoldedMap),
|
||
|
append(NewPair1s, RestOfFoldedMap, FoldedMap).
|
||
|
|
||
|
% split_pair(InputPair, OutputMap, SplittedInputPairs)
|
||
|
split_pair([Out1S, In1S, Len1], [], [[Out1S, In1S, Len1]]).
|
||
|
|
||
|
split_pair([Out1S, In1S, Len1],
|
||
|
[[Out2S, In2S, Len2] | _],
|
||
|
[[OutSNew, In1S, Len1]]) :-
|
||
|
% range1 completely inside
|
||
|
Out1S >= In2S, Out1S + Len1 =< In2S + Len2,
|
||
|
OutSNew is Out2S + (Out1S - In2S).
|
||
|
|
||
|
split_pair([Out1S, In1S, Len1],
|
||
|
[[_, In2S, Len2] | RestOf2],
|
||
|
Split) :-
|
||
|
% no overlap
|
||
|
(Out1S >= In2S + Len2; Out1S + Len1 =< In2S),
|
||
|
split_pair([Out1S, In1S, Len1], RestOf2, Split).
|
||
|
|
||
|
split_pair([Out1S, In1S, Len1],
|
||
|
[[Out2S, In2S, Len2] | RestOf2],
|
||
|
[[OutLeftS, In1S, LenLeft] | RestOfSplit]) :-
|
||
|
% range1 overlaps to the right
|
||
|
Out1S >= In2S, Out1S < In2S + Len2, Out1S + Len1 > In2S + Len2,
|
||
|
LenLeft is In2S + Len2 - Out1S,
|
||
|
OutLeftS is Out2S + (Out1S - In2S),
|
||
|
OutRightS is In2S + Len2,
|
||
|
InRightS is In1S + LenLeft,
|
||
|
LenRight is Len1 - LenLeft,
|
||
|
split_pair([OutRightS, InRightS, LenRight], RestOf2, RestOfSplit).
|
||
|
|
||
|
split_pair([Out1S, In1S, Len1],
|
||
|
[[Out2S, In2S, Len2] | RestOf2],
|
||
|
[[Out2S, InRightS, LenRight] | RestOfSplit]) :-
|
||
|
% range1 overlaps to the left
|
||
|
Out1S < In2S, Out1S + Len1 > In2S, Out1S + Len1 =< In2S + Len2,
|
||
|
LenLeft is In2S - Out1S,
|
||
|
InRightS is In1S + LenLeft,
|
||
|
LenRight is Len1 - LenLeft,
|
||
|
split_pair([Out1S, In1S, LenLeft], RestOf2, RestOfSplit).
|
||
|
|
||
|
split_pair([Out1S, In1S, Len1],
|
||
|
[[Out2S, In2S, Len2] | RestOf2],
|
||
|
[[Out2S, InMiddleS, Len2] | RestOfSplit]) :-
|
||
|
% range1 completely covers range2
|
||
|
Out1S < In2S, Out1S + Len1 > In2S + Len2,
|
||
|
LenLeft is In2S - Out1S,
|
||
|
InMiddleS is In1S + LenLeft,
|
||
|
split_pair([Out1S, In1S, LenLeft], RestOf2, SplitLeft),
|
||
|
OutRightS is In2S + Len2,
|
||
|
InRightS is In1S + LenLeft + Len2,
|
||
|
LenRight is Len1 - LenLeft - Len2,
|
||
|
split_pair([OutRightS, InRightS, LenRight], RestOf2, SplitRight),
|
||
|
append(SplitLeft, SplitRight, RestOfSplit).
|
||
|
|
||
|
% converts given ranges to sorted closed intervals starting at 0
|
||
|
process_map(Map, ProcessedMap) :-
|
||
|
sort(2, @=<, Map, SortedMap),
|
||
|
pad_start(SortedMap, Sorted0PaddedMap),
|
||
|
pad_end(Sorted0PaddedMap, ProcessedMap).
|
||
|
|
||
|
% add 0 range at the beginning if not exist. Range must be already sorted.
|
||
|
pad_start([[OutS, 0, Len] | RRanges], [[OutS, 0, Len] | RRanges]).
|
||
|
pad_start([[OutS, InS, Len] | RRanges],
|
||
|
[[0, 0, InS], [OutS, InS, Len] | RRanges]) :-
|
||
|
InS =\= 0.
|
||
|
|
||
|
% add MAXINT range at end. Range must be already sorted.
|
||
|
pad_end(Ranges, PaddedRanges) :-
|
||
|
reverse(Ranges, [[OutS, InS, Len] | RestOfRevRanges]),
|
||
|
NewInS is InS + Len,
|
||
|
NewLen is 4294967295 - NewInS,
|
||
|
(NewLen =:= 0 ->
|
||
|
reverse([[OutS, InS, Len] | RestOfRevRanges], PaddedRanges);
|
||
|
reverse([[NewInS, NewInS, NewLen], [OutS, InS, Len] | RestOfRevRanges],
|
||
|
PaddedRanges)
|
||
|
).
|
||
|
|
||
|
% convert seed ranges into a straight map
|
||
|
seed_map([], []).
|
||
|
seed_map([Start, Len | RestOfSeeds], [[Start, Start, Len] | RestOfMap]) :-
|
||
|
seed_map(RestOfSeeds, RestOfMap).
|
||
|
seed_map(Map) :- seeds(Seeds), seed_map(Seeds, Map).
|