diff --git a/08/part2.pl b/08/part2.pl index 76cee23..44a9f4b 100644 --- a/08/part2.pl +++ b/08/part2.pl @@ -10,15 +10,16 @@ answer(Answer) :- % unify2 combines 2 routes into one with its own stride-offsets-dests unify2(Route1, Route2, NewRoute) :- + writef('Combining %t + %t', [Route1, Route2]), once(findnsols(2, S, converge(Route1, Route2, S), SolutionPair)), SolutionPair = [NewA-LenA-NewZ, _-LenB-_], NewStride is LenB - LenA, - NewRoute = NewA-(NewStride-LenA-[0-NewZ]). + NewRoute = NewA-(NewStride-LenA-[0-NewZ]), + writef(' --> %t\n', [NewRoute]). % Len = Stride1*X1 + Offset1 + Dest1 = Stride2*X2 + Offset2 + Dest2 % For performance, Route1's Stride should =< Route2's Stride converge(Route1, Route2, NewA-Len-NewZ) :- - writef('Combining %t - %t\n', [Route1, Route2]), Route1 = A1-(Stride1-Offset1-Dests1), Route2 = A2-(Stride2-Offset2-Dests2), natnum(X2), @@ -28,42 +29,38 @@ converge(Route1, Route2, NewA-Len-NewZ) :- atom_concat(A1, A2, NewA), atom_concat(Z1, Z2, NewZ). routes(Starts, Routes) :- - maplist([S, S-Route]>>(zloop(S, Route)), Starts, Routes). + maplist([S, S-Route]>>(route_at(S, Route)), Starts, Routes). -% zloop builds a route (Stride-Offset-Internals) for a particular starting node. -zloop(Node, Route) :- zloop([], Node, 0, [], Route). -zloop(_Direction, _Node, _Index, Zs, Stride-Offset-Dests) :- - Zs = [FirstZIndex-Z | _], reverse(Zs, [LastZIndex-Z | ReversedZs]), - DeltaZ is LastZIndex - FirstZIndex, DeltaZ =\= 0, - direction_len(Len), - divmod(DeltaZ, Len, _, 0), - Offset = FirstZIndex, Stride = DeltaZ, - foldl([Idx-Z, NewIdx-Z, Off, Off]>>(NewIdx is Idx - Off), - ReversedZs, ReversedDests, Offset, _), - reverse(ReversedDests, Dests), +% route_at(N, Node, Dests, AllDests) means going N steps will arrive at Node +% passing through Dests. +route_at(Start, Route) :- route_at(0, Start, [], Route). +route_at(N, FirstZ, [FirstZN-FirstZ | Zs], Stride-Offset-AllZs) :- + Stride is N - FirstZN, direction_looped(Stride), + Offset is FirstZN, + maplist({Offset}/[N-X, M-X]>>(M is N-Offset), [FirstZN-FirstZ | Zs], AllZs), !. -zloop(Directions, Node, Index, Zs, Route) :- - ( is_end(Node) - -> append(Zs, [Index-Node], NewZs) - ; NewZs = Zs - ), - next_step(Directions, Move, Remain), - G =.. [Move, Node, To], G, - NewIndex is Index + 1, - zloop(Remain, To, NewIndex, NewZs, Route). +route_at(N, At, Dests, AllDests) :- + ( is_end(At) + -> append(Dests, [N-At], NextDests) + ; NextDests = Dests), + Nplus1 is N + 1, step_at(N, Step), call(Step, At, NextNode), + route_at(Nplus1, NextNode, NextDests, AllDests). starts(Starts) :- findall(X, X to _, Nodes), include(is_start, Nodes, Starts). is_start(Node) :- atom_chars(Node, [_, _, a]). is_end(Node) :- atom_chars(Node, [_, _, z]). -next_step([Move | Remain], Move, Remain). -next_step([], Move, Remain) :- direction_list([Move | Remain]). +% Step is the N-th step (counting starts from 0). +step_at(N, Step) :- + direction_list(Dir), length(Dir, DirLen), Remainder is N mod DirLen, + nth0(Remainder, Dir, Step). direction_list(Dir) :- direction(Str), atom_chars(Str, Dir). -direction_len(Len) :- direction_list(D), length(D, Len). +direction_looped(Len) :- direction_list(D), length(D, DLen), 0 is Len mod DLen. -% pick([[1,2,3], [4], [5,6]], X). X = [1,4,5]; X = [1,4,6]; X = [2,4,5]; ... +% pick one item from each sublist of ListOfLists & put them into Items in order. +% [[1,2,3], [4], [5,6]] -> [1,4,5]; [1,4,6]; [2,4,5]; [2,4,6]; [3,4,5]; [3,4,6]. pick(ListOfLists, Items) :- maplist([SubList, X]>>(member(X, SubList)), ListOfLists, Items).