:- module(_,[hanoi/5],[assertions,regtypes,nativeprops]).

:- entry hanoi(A,B,C,D,E)
         : ( num(A), elem(B), elem(C), elem(D), term(E) ).

:- pred hanoi(A,B,C,D,E)
         : ( num(A), elem(B), elem(C), elem(D), term(E) ).

hanoi(A, B, C, D, E) :- hanoi_(A, B, C, D, E).

:- pred hanoi_(A,B,C,D,E)
         : ( num(A), elem(B), elem(C), elem(D), term(E) )
        => ( num(A), elem(B), elem(C), elem(D), moves(E) ).

hanoi_(1,A,_1,C,[mv(A,C)]) :- !.
hanoi_(N,A,B,C,M) :-
        N1 is N-1,
        hanoi_(N1,A,C,B,M1),
        hanoi_(N1,B,A,C,M2),
        append(M1,[mv(A,C)],T),
        append(T,M2,M).

:- pred append(_A,L,_B)
         : ( moves(_A), moves(L), term(_B) )
        => ( moves(_A), moves(L), moves(_B) ).

append([],L,L).
append([X|L1],L2,[X|L3]) :-
        append(L1,L2,L3).

:- regtype elem/1.
elem(a).
elem(b).
elem(c).

:- regtype move/1.
move(mv(A,B)) :- elem(A), elem(B).

:- regtype moves/1.
moves([]).
moves([M|Ms]) :- move(M), moves(Ms).
