• Aucun résultat trouvé

4.5 Exemples d’utilisation des tableaux

4.5.4 Jouons `a l’escarmouche

4.5.3 Le crible d’Eratosthene

On cherche ici `a trouver tous les nombres premiers de l’intervalle [1, N]. La solution d´ej`a connue des grecs consiste `a ´ecrire tous les nombres de l’intervalle les uns `a la suite des autres. Le plus petit nombre premier est 2. On raye alors tous les multiples de 2 plus grands que 2 de l’intervalle, ils ne risquent pas d’ˆetre premiers. Le premier nombre qui n’a pas ´et´e ray´e au-del`a du nombre premier courant est lui-mˆeme premier, c’est le suivant `a traiter. On raye ainsi les multiples de 3 sauf 3, etc. On s’arrˆete quand on s’apprˆete `a ´eliminer les multiples de p >√

N (rappelons que tout nombre non premier plus petit que N a un diviseur premier 6√

N).

Comment mod´eliser le crible ? On utilise un tableau de bool´eensestpremier[N+1]

qui repr´esentera l’intervalle [1, N]. Il est initialis´e `atrue au d´epart, car aucun nombre n’est ray´e. `A la fin du calcul,p≥2 est premier ssiestpremier[p] == true. On trouve le programme complet dans la figure 4.1.

Remarquons que la ligne kp = 2*p;

peut ˆetre avantageusement remplac´ee par kp = p*p;

car tous les multiples de p de la forme upavec u < p ont d´ej`a ´et´e ray´es du tableau `a une ´etape pr´ec´edente.

Il existe de nombreuses astuces permettant d’acc´el´erer le crible. Notons ´egalement que l’on peut se servir du tableau des nombres premiers pour trouver les petits facteurs de petits entiers. Ce n’est pas la meilleure m´ethode connue pour trouver des nombres premiers ou factoriser les nombres qui ne le sont pas. Revenez donc me voir en Majeure 2 si ¸ca vous int´eresse.

4.5.4 Jouons `a l’escarmouche

On peut ´egalement se servir de tableaux pour repr´esenter des objets a priori plus compliqu´es. Nous allons d´ecrire ici une variante simplifi´ee du c´el`ebre jeu de bataille, que nous appelerons escarmouche. La r`egle est simple : le donneur distribue 32 cartes (num´erot´ees de 1 `a 32) `a deux joueurs, sous la forme de deux piles de cartes, face sur le dessous. `A chaque tour, les deux joueurs, appel´es Alice et Bob, retournent la carte du dessus de leur pile. Si la carte d’Alice est plus forte que celle de Bob, elle marque 1

// Retourne le tableau des nombres premiers de l’intervalle [2..N]

static int[] Eratosthene(int N){

boolean[] estpremier = new boolean[N+1];

int p, kp, nbp;

// initialisation

for(int n = 2; n < N+1; n++) estpremier[n] = true;

// boucle d’´elimination p = 2;

while(p*p <= N){

// ´elimination des multiples de p

// on a d´ej`a ´elimin´e les multiples de q < p kp = 2*p; // ( cf. remarque)

while(kp <= N){

estpremier[kp] = false;

kp += p;

}

// recherche du nombre premier suivant do{

p++;

} while(!estpremier[p]);

}

// comptons tous les nombres premiers <= N nbp = 0;

for(int n = 2; n <= N; n++) if(estpremier[n])

nbp++;

// mettons les nombres premiers dans un tableau int[] tp = new int[nbp];

for(int n = 2, i = 0; n <= N; n++) if(estpremier[n])

tp[i++] = n;

return tp;

}

Fig. 4.1 – Crible d’Eratosthene.

point ; si sa carte est plus faible, c’est Bob qui marque 1 point. Gagne celui des deux joueurs qui a marqu´e le plus de points `a la fin des piles.

Le programme de jeu doit contenir deux phases : dans la premi`ere, le programme bat et distribue les cartes entre les deux joueurs. Dans un second temps, le jeu se d´eroule.

Nous allons stocker les cartes dans un tableau donne[0..32[ avec la convention que la carte du dessus se trouve en position 31.

Pour la premi`ere phase, battre le jeu revient `a fabriquer une permutation au ha-sard des ´el´ements du tableau donne. L’algorithme le plus efficace pour cela utilise un g´en´erateur al´eatoire (la fonction Math.random()de Java, qui renvoie un r´eel al´eatoire entre 0 et 1), et fonctionne suivant le principe suivant. On commence par tirer un indice iau hasard entre 0 et 31 et on permutedonne[i]et donne[31]. On continue alors avec le reste du tableau, en tirant un indice entre 0 et 30, etc. La fonction Java est alors (nous allons ici syst´ematiquement utiliser le passage par r´ef´erence des tableaux) :

static void battre(int[] donne){ int n = donne.length, i, j, tmp;

for(i = n-1; i > 0; i--){

// on choisit un entier j de [0..i]

j = (int) (Math.random() * (i+1));

// on permute donne[i] et donne[j]

tmp = donne[i]; donne[i] = donne[j]; donne[j] = tmp;

} }

La fonction qui cr´ee une donne `a partir d’un paquet de ncartes est alors : static int[] jeu(int n){

int[] jeu = new int[n];

for(int i = 0; i < n; i++) jeu[i] = i+1;

battre(jeu);

return jeu;

}

et nous donnons maintenant le programme principal : public static void main(String[] args){

int[] donne;

donne = jeu(32);

jouer(donne);

}

Nous allons maintenant jouer. Cela se passe en deux temps : dans le premier, le donneur distribue les cartes entre les deux joueurs, Alice et Bob. Dans le second, les deux joueurs jouent :

static void jouer(int[] donne){

int[] jeuA = new int[donne.length/2];

int[] jeuB = new int[donne.length/2];

distribuer(jeuA, jeuB, donne);

jouerAB(jeuA, jeuB);

}

Le tableau donne[0..31]est distribu´ee en deux tas, en commen¸cant par Alice, qui va recevoir les cartes de rang pair, et Bob celles de rang impair. Les cartes sont donn´ees

`a partir de l’indice 31 :

// donne[] contient les cartes qu’on distribue `a partir de la fin // on remplit jeuA et jeuB `a partir de 0

static void distribuer(int[] jeuA, int[] jeuB, int[] donne){ int iA = 0, iB = 0;

for(int i = donne.length-1; i >= 0; i--){ if((i % 2) == 0)

jeuA[iA++] = donne[i];

else

jeuB[iB++] = donne[i];

} }

Il ne reste plus qu’`a jouer et `a afficher le gagnant. On introduit les deux variables gainA et gainB qui contiennent le nombre de fois o`u la carte de rang id’Alice (resp.

Bob) est de valeur plus forte que celle de Bob (resp. Alice) : static void jouerAB(int[] jeuA, int[] jeuB){

int gainA = 0, gainB = 0;

for(int i = jeuA.length-1; i >= 0; i--){ if(jeuA[i] > jeuB[i])

gainA++;

else

gainB++;

}

if(gainA > gainB) System.out.println("A gagne");

else System.out.println("B gagne");

}

Exercice.(Programmation du jeu de bataille) Dans le jeu de bataille (toujours avec les cartes 1..32), le joueur qui remporte un pli le stocke dans une deuxi`eme pile `a cˆot´e de sa pile courante, les cartes ´etant stock´ees dans l’ordre d’arriv´ee, formant une nouvelle pile. Quand il a fini sa premi`ere pile, il la remplace par la seconde et continue `a jouer.

Le jeu s’arrˆete quand un des deux joueurs n’a plus de cartes. Programmer ce jeu.