diff --git a/08/part2.pl b/08/part2.pl index cb94866..f8464dd 100644 --- a/08/part2.pl +++ b/08/part2.pl @@ -5,51 +5,32 @@ From r To :- From to _-To. answer(Answer) :- starts(Starts), - routes(Starts, Routes), - collapse_routes(Routes, _-(_-Answer-_)). - -collapse_routes([X], X). -collapse_routes(Routes, Collapsed) :- - writef('Collapsing: %t\n', [Routes]), - sort(2, @=<, Routes, [Route1, Route2 | CdrRoutes]), - unify2(Route1, Route2, NewRoute), - collapse_routes([NewRoute | CdrRoutes], Collapsed). + routes(Starts, [Route1 | RestOfRoutes]), + foldl(unify2, RestOfRoutes, Route1, Answer). % unify2 combines 2 routes into one with its own stride-offsets-dests -unify2(Route1, Route2, Route12) :- unify2(Route1, Route2, 0-0-0-0, [], Route12). -unify2(Route1, Route2, N1-Dest1-N2-Dest2, Founds, NewRoute) :- +unify2(Route1, Route2, NewRoute) :- + once(findnsols(2, S, converge(Route1, Route2, S), SolutionPair)), + SolutionPair = [NewA-LenA-NewZ, _-LenB-_], + NewStride is LenB - LenA, + NewRoute = NewA-(NewStride-LenA-[0-NewZ]). + +% 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), - nth0(Dest1, Dests1, C1-Z1), - nth0(Dest2, Dests2, C2-Z2), - Len1 is Offset1 + Stride1*N1 + C1, - Len2 is Offset2 + Stride2*N2 + C2, - next(Dests1, N1-Dest1, NextN1-NextDest1), - ( Len1 =:= Len2 - -> ( Founds = [OldLen] - -> atom_concat(A1, A2, NewA), atom_concat(Z1, Z2, NewZ), - NewStride is Len1 - OldLen, - NewRoute = NewA-(NewStride-OldLen-[0-NewZ]), - ! - ; unify2(Route1, Route2, NextN1-NextDest1-N2-Dest2, [Len1], NewRoute) - ) - ; Len1 < Len2 - -> unify2(Route1, Route2, NextN1-NextDest1-N2-Dest2, Founds, NewRoute) - ; next(Dests2, N2-Dest2, NextN2-NextDest2), - unify2(Route1, Route2, N1-Dest1-NextN2-NextDest2, Founds, NewRoute) - ). - -% next(Dests, NumberOfLoops-WhichInternalZ, NextNumberOfLoops-NextInternalZ) -next(Dests, NLoops-Dest, NextNLoops-NextDest) :- - length(Dests, DestsLen), - ( Dest < DestsLen - 1 - -> NextNLoops is NLoops, NextDest is Dest + 1 - ; NextNLoops is NLoops + 1, NextDest is 0). + natnum(X2), + pick([Dests1, Dests2], [Dest1-Z1, Dest2-Z2]), + 0 is (Stride2*X2 + Offset2 + Dest2 - Offset1 - Dest1) mod Stride1, + Len is Stride2*X2 + Offset2 + Dest2, + atom_concat(A1, A2, NewA), atom_concat(Z1, Z2, NewZ). routes(Starts, Routes) :- maplist([S, S-Route]>>(zloop(S, Route)), Starts, Routes). -% zloop builds a route (Stride-Offset-Internals for a particular starting node. +% 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]), @@ -81,3 +62,10 @@ next_step([], Move, Remain) :- direction_list([Move | Remain]). direction_list(Dir) :- direction(Str), atom_chars(Str, Dir). direction_len(Len) :- direction_list(D), length(D, Len). + +% pick([[1,2,3], [4], [5,6]], X). X = [1,4,5]; X = [1,4,6]; X = [2,4,5]; ... +pick(ListOfLists, Items) :- + maplist([SubList, X]>>(member(X, SubList)), ListOfLists, Items). + +natnum(0). +natnum(N) :- natnum(N0), N is N0 + 1. diff --git a/08/test2.pl b/08/test2.pl index e19c125..52fdcc4 100644 --- a/08/test2.pl +++ b/08/test2.pl @@ -8,4 +8,12 @@ nna to nnb-xxx. nnb to nnc-nnc. nnc to nnz-nnz. nnz to nnb-nnb. +ooa to ooz-oob. +oob to ood-ooc. +ooc to ooa-oox. +ood to ooz-ood. +ooz to oob-ooz. xxx to xxx-xxx. + +% Routes = [mma-(2-2-[0-mmz]), nna-(6-3-[0-nnz, 3-nnz]), ooa-(8-1-[0-ooz, 1-ooz])]. +% X = mmannaooa-(24-18-[0-mmznnzooz]).