/* 1  */

exp(N,0,1):- N>=0.
exp(0,N,0):- N>0.
exp(N,M,R):- N>0, M>0,P is M-1, exp(N,P,Q), R is Q*N.

tour_exp(N,0,N):- N>=0.
tour_exp(0,N,0):- N>0.
tour_exp(N,M,R):- M >0, N>0, P is M-1, tour_exp(N,P,Q), exp(Q,N,R).

monstre(N,0,N):- N>=0.
monstre(0,N,0):- N>0.
monstre(N,M,R):- M >0, N>0,  P is M-1, monstre(N,P,Q), exp(N,Q,R).


/* 2  */

member(X,[X|_]):- !.
member(X,[_|T]):- member(X,T).

d([],[]).
d([X|L],R):- d(L,R),member(X,R).
d([X|L],[X|R]):- d(L,R),not(member(X,R)).

d1([],[]).
d1([X|L],R):-d1(L,R),member(X,R).
d1([X|L],[X|R]):-d1(L,R).

d2([],[]).
d2([X|L],R):-d2(L,R),member(X,R),!.
d2([X|L],[X|R]):-d2(L,R).

d3([],[]).
d3([X|L],R):-d3(L,R),!,member(X,R).
d3([X|L],[X|R]):-d3(L,R).

/* d(+L1,-L2) unifie L2 avec une liste qui a les memes elements que L1, */
/* sans doublons, par effacement des doublons de la tete de L1. */
/* Par exemple d([1,3,2,1,3], R) donne comme unique  resultat R=[2,1,3] */


/* d1,d2,d3 ont meme sem declarative, car la coupure equivaut logiquement*/
/* a true */
/* d a une semantique declarative differente de ces trois. */
/* car par exemple */
/*   d([1,1], [1,1]) est faux et  d1([1,1], [1,1]) est vrai. */

/* d et d2 ont meme sem. operationnelle, car les deux premisses */
/* member(X,L),! dans d2 ont  meme effet que les premisses */
/* member(X,L)...non(member(X,L)) de d (exclusion mutuelle) */
/* par contre, les semantiques operationnelles de d1 et d3 */
/* sont differentes entre elles et differentes de celle de d: */
/* par exemple: */
/* d3([1,1], R) echoue et d1([1,1], R) donne deux */
/* resultats R=[1] et R=[1,1] */

/* 3 */


move(N,P):-(N>=3, P is N-3); (N>=2, P is N-2); (N>=1, P is N-1). 

gagne(0).
gagne(N):- move(N,P),not(gagne(P)).


mod(X,Y,X):-X<Y,!.
mod(X,Y,Z):- T is X-Y, mod(T,Y,Z).


/* (77,J) vaut 0 */

gagne1(P):-mod(P,4,X), X=\=1.