:- table direction_loop/1. :- op(700, xfx, l). :- op(700, xfx, r). From l To :- From to To-_. From r To :- From to _-To. % We want to satisfy {Offset_i + Stride_i*Loops_i + Sub_ij = Z} answer() :- starts(Starts), maplist([S, S-Off-Stride-Loop]>>(zloop([], S, 0, [], Off, Stride, Loop)), Starts, Events), maplist(split, Events, EquationSets), pick(EquationSets, Eqs), index1(Eqs, IEqs), write('Find N_i such that: '), foldl(write_eq, IEqs, _, _), write('Z\n'), % foldl(satisfy, EquationsN, _, Answer), true. write_eq(I-(A-B-C), _, _) :- writef('%t + %t*N%t ', [A, B, I]), (C =\= 0 -> writef('+ %t ', [C]); true), write('= '). % satisfy((A-B-C), N, Z, Z) :- natnum(N), Z is A + B*N + C. % [mma-2-2-[0-mmz], nna-3-6-[0-nnz, 3-nnz]] -> [2-2-0, 3-6-0, 3-6-3] split(_-_-_-[], []). split(A-Offset-Stride-[Sub-_ | Loop], [Offset-Stride-Sub | Cdr]) :- split(A-Offset-Stride-Loop, Cdr). % Everything above this is not needed to get the input answer % starts(Starts), % maplist([S, S-Off-Stride-Loop]>>(zloop([], S, 0, [], Off, Stride, Loop)), % Starts, Loops). % then find the LCD of the strides (which are equal to offsets). zloop(_, _, _, Zs, Offset, Stride, Loop) :- 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, ReversedLoop, Offset, _), reverse(ReversedLoop, Loop), !. zloop(Directions, Node, Index, Zs, Offset, Stride, Loop) :- ( 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, Offset, Stride, Loop). 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]). 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). index1(L, IL) :- reverse(L, RL), index1r(RL, IRL), reverse(IRL, IL). index1r([X], [1-X]). index1r([X, Y | Cdr], [NextI-X, I-Y | ICdr]) :- index1r([Y | Cdr], [I-Y | ICdr]), NextI is I + 1. same_elements([_]). same_elements([X-_, Y-Z2 | Cdr]) :- X =:= Y, same_elements([Y-Z2 | Cdr]). natnum(0). natnum(N) :- natnum(N0), N is N0 + 1.