Sunteți pe pagina 1din 39

Algorithmes rcursifs : exemples dapplications

Algorithmique et programmation (Licence 1 - S2)

Algorithmique et programmation (Licence 1 - S2)

1/39

Rcursivit : rappel du principe


Une fonction est une mthode pour dfinir des algorithmes rutilisables avec diffrents
paramtres.

Une fonction rcursive est une fonction qui peut sappeler elle-mme.

paramtres

Algorithmique et programmation (Licence 1 - S2)

retour

2/39

Construction dun algorithme rcursif


Un peu comme pour dfinir une suite par rcurrence en maths, il faut :
1. un (ou plusieurs) cas de base, dans laquelle lalgorithme ne sappelle pas lui-mme.
Sinon lalgorithme ne peut pas terminer.
2. si on ne se situe pas dans un cas de base (on parle de cas inductif ), lalgorithme
fait appel lui-mme (appel rcursif ).
Chaque appel rcursif doit en principe se rapprocher dun cas de base, de faon
permettre la terminaison du programme.

Algorithmique et programmation (Licence 1 - S2)

3/39

Exemple avec factoriel


fonction factorielle (n : entier) retourne entier
debut
si n=0 alors retourner 1 (cas de base)
sinon retourner n * factorielle (n-1)
fin

Cette fonction retourne n! si n est positif ou nul, et ne termine pas si n est ngatif (appels
rcursifs infinis).

Note : concrtement, si n est ngatif le programme provoque (le plus souvent) une erreur
lexcution pour cause de dpassement de mmoire autoris dans les appels de fonctions
(pile dappel).

Algorithmique et programmation (Licence 1 - S2)

4/39

Environnement des fonctions rcursives


Point essentiel : chaque appel rcursif dispose de ses propres variables locales.
Cest ce qui permet la rcursivit dtre utile.
Avec ce programme :
int combi (int n,int p)
{
int a,b;
if ((p==0) || (p==n)) return 1;
else
{
a = combi(n-1,p-1);
b = combi(n-1,p);
return a+b;
}
}

Les variables a et b sont redclares chaque appel. Ceci est bien entendu galement vrai
pour les paramtres.
Algorithmique et programmation (Licence 1 - S2)

5/39

Environnement : variable globale


Si on veut partager une variable, il faut la dclarer en dehors de la fonction : Avec ce
programme :
int a,b;
int pascombi (int n, int p)
{
if ((p==0) || (p==n)) return 1;
else
{
a = pascombi(n-1,p-1);
b = pascombi(n-1,p);
return a+b;
}
}

Ici pascombi(4,2) retourne 5.


Algorithmique et programmation (Licence 1 - S2)

6/39

Fonctionnement de la rcursivit
Lappel des fonctions fonctionne laide dune pile dexcution qui conserve les contextes
dappel :
1. chaque appel de fonction, on empile le contexte : lieu de lappel, variables locales,
etc...
2. chaque retour de fonction, on dpile le contexte, ce qui permet de revenir au point
dappel.
(1)void fonc1(int a) { (2) (3)
int main() {

(0)

Pile dexecution
if (a>0)
l. 8 fonc1(a1)

l.21 fonc1 (2);


}

main, l.21

fonc1, l.8
a=2
main, l.21

fonc1, l.8
a=1
fonc1, l.8
a=2
main, l.21

(4) (5)
(6) }

(0)

(1)

( debut )

(appel de
fonc1(2) )

(6)

(5)

(2)
(appel de
fonc1(1) )

(3)
(appel de
fonc1(0) )

(4)

( retour
( retour
( retour
de fonc1(2) ) de fonc1(1) ) de fonc1(0) )

La rcursivit permet dexploiter au mieux toutes les possibilits de cette pile.


Algorithmique et programmation (Licence 1 - S2)

7/39

Rcursion contre itrations


Consquence : tout algorithme rcursif peut tre transform en un algorithme itratif
(avec des boucles) sans rcursion, en utilisant une pile construite et gre dans le programme. Mais :
la pile dexcution existe dj moins de travail ;
elle peut manipuler nimporte quel type de donnes plus facile ;
la rcursivit peut tre plus naturelle pour un problme donn plus lisible ;
les processeurs sont optimiss pour grer cette pile plus rapide.
Cela peut tre intressant si on veut contrler exactement la gestion de la pile (par
exemple, revenir brutalement de plusieurs appels en arrire).

Algorithmique et programmation (Licence 1 - S2)

8/39

Itrations contre rcursion

while (c) {
/* ... bloc ... */
}

void fonctionrec() {
if ( !c) {
/* ... bloc ... */
fonctionrec() ;
}
}

Rciproque : tout algorithme itratif peut tre transform en algorithme rcursif sans
boucle (en grant convenablement les variables). Mais :
a peut tre moins lisible ;
chaque itration prend un peu de place en mmoire (occupe la pile) ;
la gestion des variables peut tre plus complique.
Pour des algorithmes de nature diffrente (par exemple les calculs de Fibonacci itratifs
et rcursifs vus en cours/TD), la complexit peut tre diffrente. Il est trs facile de faire
des algorithmes de complexit exponentielle avec la rcursivit.
Algorithmique et programmation (Licence 1 - S2)

9/39

Intrt des algorithmes rcursifs


Essentiellement, deux intrts (pas si diffrents) :
1. dcomposer une action rptitive en sous-actions identiques de petits tailles :
pour rechercher un lment dans un tableau tri, ou pour trier un tableau (trifusion), on parle de diviser pour rgner .
pour dessiner ou faire des structures fractales (cf TP 5).
2. pour explorer un ensemble de possibilits (par exemple des coups dans un jeu), on
peut faire un appel rcursif sur chaque possibilit. La conservation des environnements
locaux permet de revenir en arrire.

Algorithmique et programmation (Licence 1 - S2)

10/39

Exemple 1 : les tours de Hano


Le problme des tours de Hano est une application classique de la rcursivit. Une tour
est constitu dun ou plusieurs disques de tailles variables. On dispose de 3 tours .
Initialement, la premire comprend n disques et les deux autres sont vides. Le but est de
placer les n disques sur la 3me tour, avec les rgles suivantes :
on ne peut dplacer quun disque la fois dune tour une autre ;
on ne peut poser un disque que sur un disque plus grand ou sur un emplacement vide.

Position initiale
Algorithmique et programmation (Licence 1 - S2)

Position finale

11/39

Principe de rsolution
Pour dplacer le disque le plus grand de la 1re la 3me tour, il faut que tous les autres
disques soient sur la deuxime tour :

Donc :
1. on dplace les n 1 disques plus petits de la 1re la 2me tour ;
2. on dplace le plus grand disque de la 1re la 3me tour ;
3. puis on dplacer les n 1 disques de la 2me la 3me tour.
Les tapes 1 et 3 se font par appel rcursif, en changeant le numro des tours.
Algorithmique et programmation (Licence 1 - S2)

12/39

Algorithme
fonction hanoi (nb_disques, depart, destination, intermediaire)
debut
si nb_disques = 1 alors
dplacer le disque 1 de depart vers destination
sinon
hanoi (nb_disques -1, depart, intermediaire, destination)
dplacer le disque nb_disques de depart vers destination
hanoi (nb_disques -1, intermediaire, destination, depart)
finsi
fin

Algorithmique et programmation (Licence 1 - S2)

13/39

Programme
Lalgorithme ne prcise pas ce que signifie dplacer . Si on ne veut pas reprsenter (en
mmoire) les tours, le plus simple est dafficher les actions faire.
void hanoi (int nb_disques, int depart, int destination, int intermediaire) {
if (nb_disques == 1) {
printf ("Dplacer le disque 1 de la tour %d la tour %d.\n",
depart, destination);
} else {
hanoi (nb_disques-1, depart, intermediaire, destination);
printf ("Dplacer le disque %d de la tour %d la tour %d.\n",
nb_disques, depart, destination);
hanoi (nb_disques-1, intermediaire, destination, depart);
}
}

Cette fonction termine si nb_disques est suprieur ou gal 1.


Algorithmique et programmation (Licence 1 - S2)

14/39

Exemple Avec hanoi(3,1,3,2), la fonction affiche :


Dplacer
Dplacer
Dplacer
Dplacer
Dplacer
Dplacer
Dplacer

le
le
le
le
le
le
le

disque
disque
disque
disque
disque
disque
disque

1
2
1
3
1
2
1

de
de
de
de
de
de
de

la
la
la
la
la
la
la

tour
tour
tour
tour
tour
tour
tour

1
1
3
1
2
2
1

la
la
la
la
la
la
la

tour
tour
tour
tour
tour
tour
tour

3.
2.
2.
3.
1.
3.
3.

(4)
1
2
3
hanoi(3,1,3,2)

(2)

1
(1)

2
3
hanoi(1,1,3,2)

2
3
hanoi(2,1,2,3)

(6)
1

(3)

1
2
3
hanoi(1,3,2,1)

Algorithmique et programmation (Licence 1 - S2)

(5)

2
3
hanoi(2,2,3,1)

2
3
hanoi(1,2,1,3)

(7)

2
3
hanoi(1,1,3,2)
15/39

Notes
1. Le schma de la page prcdente est un arbre binaire (chaque nud a 2 enfants).
En informatique, les arbres se reprsentent vers le bas.
2. On dit que cet arbre est parcouru en profondeur lorsquon descend le plus vite
possible vers les feuilles. La rcursivit est bien adapte pour crire un tel parcours.
3. Lordre de lecture fils gauche nud fils droit est appel lordre infixe.
4. La rcursivit permet ici :
de garder en rserve la partie droite pendant quon soccupe de la partie gauche ;
de conserver les valeurs locales de depart, destination, intermerdiaire.
Un tel algorithme serait difficile crire sans rcursivit.

Algorithmique et programmation (Licence 1 - S2)

16/39

Algorithme itratif
fonction hanoi_it (nb_disques, depart, destin, interm)
debut
p creer_pile()
empiler(p,nb_disque), empiler(p,depart), empiler(p,destin), empiler(p, interm)
tantque (non estVide(p)) faire
depiler(p,inter), depiler (p,dest), depiler (p,dep), depiler(p,nb)
si nb = 1 ou inter=0 alors
dplacer le disque nb de depart vers destination
sinon
empiler (p,nb-1), empiler(p,inter), empiler(p,dest), empiler(p,dep)
empiler (p,nb), empiler(p,dep), empiler(p,dest), empiler(p,0)
empiler (p,nb-1), empiler(p,dep), empiler(p,inter), empiler(p,dest)
finsi
fintantque
fin
Algorithmique et programmation (Licence 1 - S2)

17/39

Complexit
Combien dtapes sont ncessaires pour rsoudre le problme avec n disques ?
Si on note un ce nombre dtapes, on a :

1
un =
u

n1

si n = 1 (cas de base)
+ 1 + un1

si n > 1

Par rcurrence, on montre :


un = 2n 1
Cet algorithme a donc une complexit exponentielle (comme la solution du problme).
Pour n = 64, un ordinateur faisant 1500000 affichages la seconde prendrait 380000 ans
pour produire la solution qui occuperait 900 milliards de Go.

Algorithmique et programmation (Licence 1 - S2)

18/39

Exemple 2 : le labyrinthe
Donne du problme
Un robot se trouve dans un labyrinthe (avec des couloirs et des murs), et cherche
rcuprer un objet.

O
R

R : robot

O : objet

Le robot ne peut que sentir ce quil y a autour de lui. Il peut se dplacer dans nimporte
quelle direction.
Algorithmique et programmation (Licence 1 - S2)

19/39

Reprsentation du labyrinthe
Le labyrinthe peut se reprsenter laide dune matrice (tableau deux dimensions). Par
exemple, une case avec 0 reprsente un mur, une case avec 1 reprsente un couloir, et une
case avec 2 reprsente lobjet.
int labyrinthe[11][15] =
{ { 0, 0, 0, 0, 0, 0, 0,
{ 0, 1, 1, 1, 0, 1, 1,
{ 0, 1, 0, 1, 1, 1, 0,
{ 0, 1, 0, 0, 1, 0, 0,
{ 0, 1, 1, 0, 1, 1, 0,
{ 0, 0, 1, 0, 0, 1, 1,
{ 0, 1, 1, 1, 0, 0, 1,
{ 0, 1, 0, 1, 1, 0, 1,
{ 0, 1, 0, 0, 0, 0, 1,
{ 0, 1, 0, 1, 1, 1, 1,
{ 0, 0, 0, 0, 0, 0, 0,

0,
1,
0,
1,
1,
1,
0,
0,
0,
1,
0,

0,
1,
0,
1,
0,
0,
0,
1,
1,
1,
0,

0,
1,
0,
0,
0,
1,
0,
1,
0,
0,
0,

0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
0,

0,
1,
0,
0,
1,
0,
0,
0,
0,
1,
0,

Algorithmique et programmation (Licence 1 - S2)

0,
1,
0,
1,
1,
1,
0,
1,
0,
1,
0,

0,
1,
0,
2,
0,
1,
1,
1,
0,
1,
0,

0
0
0
0
0
0
0
0
0
0
0

},
},
},
},
},
},
},
},
},
},
} };
20/39

Principe de la recherche
La rcursivit permet dexplorer plusieurs choix ( gauche ? droite ? tout droit ?). Un
cas de base est donc quand il ny a plus de choix.
A priori, deux cas de bases :
1. le robot est dj lemplacement de lobjet : rien faire.
2. le robot est dans un cul-de-sac (cest--dire, la seule possibilit est de revenir sur ses
pas).
Sinon, le robot explore les diffrentes possibilits (appel rcursif). Si une possibilit russit
(mne lobjet), il ne doit pas continuer. Si toutes les possibilits chouent, il revient en
arrire.

Algorithmique et programmation (Licence 1 - S2)

21/39

Algorithme
La fonction doit retourner un boolen, pour savoir si on a trouv ou non lobjet.
fonction explore (pos_l, pos_c, orig_l, orig_c) retourne boolen
debut
aller en (pos_l, pos_c)
ok <- (labyrinthe[pos_l][pos_c]=2)
si (pas ok) et (pos_l -1 6= orig_l) et (labyrinthe[pos_l-1][pos_c]>0) alors
ok <- explore (pos_l -1, pos_c, pos_l, pos_c)
si (pas ok) et (pos_l+1 6= orig_l) et (labyrinthe[pos_l+1][pos_c]>0) alors
ok <- explore (pos_l +1, pos_c, pos_l, pos_c)
si (pas ok) et (pos_c+1 6= orig_c) et (labyrinthe[pos_l][pos_c+1]>0) alors
ok <- explore (pos_l, pos_c+1, pos_l, pos_c)
si (pas ok) et (pos_c-1 6= orig_c) et (labyrinthe[pos_l][pos_c-1]>0) alors
ok <- explore (pos_l, pos_c-1, pos_l, pos_c)
si (pas ok) alors aller en (orig_l, orig_c)
retourner ok
fin

Algorithmique et programmation (Licence 1 - S2)

22/39

Notes
1. Cet algorithme nest pas optimal (trop de tests rpts), mais est plus lisible (sur un
transparent).
2. Conditions de fonctionnement :
le labyrinthe doit tre entour de murs (sinon il faut tester que pos_x ou pos_y ne
sorte pas des limites du tableau) ;
le labyrinthe ne doit pas avoir de cycles, sinon lalgorithme peut boucler. On
regardera ce problme ensuite.

Algorithmique et programmation (Licence 1 - S2)

23/39

Traduction en C
int explore (int posl, int posc, int origl, int origc) {
int ok;
printf("Aller en %d,%d\n", posl, posc);
ok = (labyrinthe[posl][posc]==2);
if (!ok) {
if ((posl-1!=origl) && (labyrinthe[posl-1][posc]>0))
ok = explore(posl-1,posc,posl,posc);
if (!ok) {
if ((posl+1!=origl) && (labyrinthe[posl+1][posc]>0))
ok = explore(posl+1,posc,posl,posc);
if (!ok) {
if ((posc+1!=origc) && (labyrinthe[posl][posc+1]>0))
ok = explore(posl,posc+1,posl,posc);
if (!ok) {
if ((posc-1!=origc) && (labyrinthe[posl][posc-1]>0))
ok = explore(posl,posc-1,posl,posc);
if (!ok)
printf("Retour en %d,%d\n", origl, origc);
} } } }
return ok;
}
Algorithmique et programmation (Licence 1 - S2)

24/39

Fonction main, excution


int main () {
if (explore (6,2,-1,-1)) {
printf("Le robot a trouv lobjet !\n");
} else {
printf("Le robot na rien trouv...\n");
}
return 0;
}

Petit problme pour lorigine lors du premier appel : on peut par exemple modifier la
fonction dexploration pour ne pas afficher de retour si lorigine est (-1,-1).

Algorithmique et programmation (Licence 1 - S2)

25/39

Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller
Aller

en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en
en

6,2
5,2
4,2
4,1
3,1
2,1
1,1
1,2
1,3
2,3
2,4
3,4
4,4
4,5
5,5
5,6
6,6
7,6
8,6
9,6
9,7
9,8

Aller en 8,8
Aller en 7,8
Aller en 7,9
Aller en 7,10
Aller en 8,10
Aller en 9,10
Aller en 9,11
Aller en 9,12
Aller en 9,13
Retour en 9,12
Retour en 9,11
Retour en 9,10
Retour en 8,10
Retour en 7,10
Retour en 7,9
Retour en 7,8
Retour en 8,8
Retour en 9,8
Retour en 9,7
Retour en 9,6
Aller en 9,5
Aller en 9,4

Aller en 9,3
Retour en 9,4
Retour en 9,5
Retour en 9,6
Retour en 8,6
Retour en 7,6
Retour en 6,6
Retour en 5,6
Aller en 5,7
Aller en 4,7
Aller en 3,7
Aller en 3,8
Retour en 3,7
Retour en 4,7
Retour en 5,7
Retour en 5,6
Retour en 5,5
Retour en 4,5
Retour en 4,4
Retour en 3,4
Retour en 2,4
Aller en 2,5

Aller en 1,5
Aller en 1,6
Aller en 1,7
Aller en 1,8
Aller en 1,9
Aller en 1,10
Aller en 2,10
Aller en 3,10
Aller en 4,10
Aller en 5,10
Aller en 5,9
Retour en 5,10
Retour en 4,10
Aller en 4,11
Aller en 4,12
Aller en 3,12
Aller en 3,13
Le robot a trouv lobjet !

O
R

R : robot
R
R : robot

O : objet

R
O : objet

R : robot

O : objet

R : robot

Algorithmique et programmation (Licence 1 - S2)

O : objet

26/39

Notes
1. L encore, on a une exploration en profondeur , classique des algorithmes rcursifs.
2. Le parcours exact dpend bien entendu de lordre des choix (entre c+1, c-1, l+1, l-1),
a priori compltement arbitraire.
3. La complexit de lalgorithme est limit par la taille totale du labyrinthe.
4. Lintrt de la rcursivit est de mmoriser le chemin parcouru pour pouvoir revenir
en arrire.
5. Un cycle peut provoquer une boucle infinie (et une erreur lexcution). Par exemple :

Algorithmique et programmation (Licence 1 - S2)

27/39

Traitement des cycles


La technique la plus simple est de marquer les endroits dj explors. Si on peut, on
le fait directement sur la matrice. Par exemple, on peut ajouter la valeur (-1) pour dire
couloir dj explor :
int explore (int posl, int posc, int origl, int origc) {
int ok;
printf("Aller en %d,%d\n", posl, posc);
ok = (labyrinthe[posl][posc]==2);
if (!ok) {
labyrinthe[posl][posc]=-1;
/* case marque */
if ((posl-1!=origl) && (labyrinthe[posl-1][posc]>0))
ok = explore(posl-1,posc,posl,posc);
...

Ici cette valeur est bien adapte au reste des tests (>0 pour dsigner un couloir non explor
ou lobjet).

Algorithmique et programmation (Licence 1 - S2)

28/39

Exemple 3 : le morpion
Donne du problme
Trouver le coup jouer au morpion (sur une grille 3x3), en fonction de la situation actuelle.

Algorithmique et programmation (Licence 1 - S2)

29/39

Reprsentation du jeu
L encore, on peut utiliser une matrice (3x3). Par exemple, 0 est une case vide, 1 est une
croix, (-1) est un rond.
int jeu[3][3] = { { 0,0,0 }, { 0,0,0 }, { 0,0,0 } };

Algorithmique et programmation (Licence 1 - S2)

30/39

Etude de la situation linstant


Pour pouvoir valuer un coup, il faut donner une valeur une position de jeu. Dans un
cas simple, comme le morpion, on peut simplement donner un score de 1 si les croix ont
gagn, un score de (-1) si les ronds ont gagn, et une score de 0 si (pour linstant) personne
na gagn.
int score (int position[3][3]) {
int i = 0, resultat = 0;
while ((i<3) && (resultat==0)) {
if ((position[i][0]!=0) && (position[i][1]==position[i][0]) &&
(position[i][2]==position[i][0]))
resultat = position[i][0];
else if ((position[0][i]!=0) && (position[1][i]==position[0][i]) &&
(position[2][i]==position[0][i]))
resultat = position[0][i];
i=i+1;
}
if (resultat==0) {
if ((position[0][0]!=0) && (position[1][1]==position[0][0]) &&
(position[2][2]==position[0][0]))
resultat = position[0][0];
else if ((position[0][2]!=0) && (position[1][1]==position[0][2]) &&
(position[2][0]==position[0][2]))
resultat = position[0][2];
}
return resultat;
}

Algorithmique et programmation (Licence 1 - S2)

31/39

Calcul du score par exploration


Le calcul prcdent indique juste si une situation est gagne (ou perdue) sur le coup. On
cherche maintenant valuer une situation en fonction de lavenir. Une telle fonction doit
donc prendre en paramtre :
la situation actuelle ;
le numro du joueur (+1 ou -1) qui doit jouer.
et retourner :
1. 1 si le joueur 1 peut forcer la victoire ;
2. -1 si le joueur -1 peut forcer la victoire ;
3. 0 si aucun joueur ne peut forcer la victoire.

Algorithmique et programmation (Licence 1 - S2)

32/39

Principe du calcul
Deux cas de bases :
1. si le score linstant du jeu vaut 1 ou -1, on retourne ce score ;
2. si le score linstant vaut 0 et que le jeu est plein, on retourne 0.
Dans les autres cas, on teste les coups possibles pour le joueur actuel (appels rcursifs) :
1. si cest le joueur 1, on retourne le maximum des scores obtenu par chaque coup :
un coup qui donne un score de 1 permet dassurer que le joueur 1 peut forcer la
victoire ;
un coup qui donne un score de 0 assure au moins de ne pas perdre ;
seulement si tous les coups sont -1, on doit retourner -1.
2. si cest le joueur -1, on retourne le minimum des scores obtenus.
Cette alternance de calculs minimum/maximum est appel algorithme minmax (ou
minimax).
Algorithmique et programmation (Licence 1 - S2)

33/39

Fonction en C
int minimax (int position[3][3], int joueur) {
int resultat, i, j, resultat_coup, coups_possibles =0;
resultat = score (position);
if (resultat==0) {
resultat = -joueur; /* pire cas */
for (i=0;i<3;i=i+1) {
for (j=0;j<3;j=j+1) {
if (position[i][j]==0) {
position[i][j]=joueur;
/*
resultat_coup = minimax (position, -joueur); /*
position[i][j]=0;
/*
coups_possibles=1;
if (resultat_coup*joueur > resultat*joueur) {
resultat = resultat_coup;
}
}
}
}
if (coups_possibles==0) resultat = 0; /* jeu bloqu =
}
return resultat;
}
Algorithmique et programmation (Licence 1 - S2)

coup "virtuel" */
appel rcursif */
retour arrire */

match nul */

34/39

Utilisation
En modifiant lgrement le code, on peut mmoriser le (ou un) meilleur coup possible et
le jouer.
/* on suppose que la position nest pas finale */
void jouer (int position[3][3], int joueur) {
int resultat, i, j, resultat_coup, i_mieux, j_mieux;
resultat = -2*joueur; /* pour tre sur de mmoriser au
for (i=0;i<3;i=i+1) {
for (j=0;j<3;j=j+1) {
if (position[i][j]==0) {
position[i][j]=joueur;
/*
resultat_coup = minimax (position, -joueur); /*
position[i][j]=0;
/*
if (resultat_coup*joueur > resultat*joueur) {
resultat = resultat_coup;
i_mieux = i;
j_mieux = j;
}
}
} }
position[i_mieux][j_mieux]=joueur;
printf ("Le joueur %d joue en %d,%d.",joueur, i_mieux,
}
Algorithmique et programmation (Licence 1 - S2)

moins un coup */

coup "virtuel" */
calcul score */
retour arrire */

j_mieux);
35/39

Programme principal
On fait jouer un humain contre lordinateur (qui commence) :
int main () {
int joueur = 1, nb_libre = 9, score_actuel = 0;
while ((nb_libre>0) && (score_actuel==0)) {
if (joueur==1) { /* ordinateur */
jouer (jeu, 1);
} else {
/* joueur humain */
int i,j;
printf("Entrez votre coup : ");
scanf("%d",&i);
scanf("%d",&j);
jeu[i][j]=-1;
/* trs mauvais : aucun test derreur */
}
score_actuel = score (jeu);
nb_libre = nb_libre - 1;
joueur = -joueur;
}
if (score_actuel ==0) printf ("Match nul !\n");
else if (score_actuel ==1) printf("Lordinateur a gagn !\n");
else printf("Vous avez gagn (et trich).\n");
return 0;
}
Algorithmique et programmation (Licence 1 - S2)

36/39

Excution
Le joueur 1 joue en 0,0.
Entrez votre coup : 2 2
Le joueur 1 joue en 0,2.
Entrez votre coup : 0 1
Le joueur 1 joue en 2,0.
Entrez votre coup : 1 0
Le joueur 1 joue en 1,1.
Lordinateur a gagn !

Algorithmique et programmation (Licence 1 - S2)

37/39

Notes
1. Lordinateur joue parfaitement, sans aucun hasard ni intelligence . Tant quil nest
pas sr de pouvoir gagner, il ne cherche assurer que le match nul (en supposant son
adversaire de mme niveau).
2. La technique utilise est (encore) une exploration en profondeur de lensemble des
parties possibles (soit, initialement, 255 168 parties).
3. La complexit de lalgorithme dpend du nombre de combinaisons possibles modr
pour un jeu comme le morpion 3x3.
Lalgorithme du minmax, avec des optimisations (voir lagage alphabta), est la base
des joueurs automatiques dans les jeux de stratgies classiques (sans hasard).

Algorithmique et programmation (Licence 1 - S2)

38/39

Application dautres jeux


La complexit augmente exponentiellement ds que le jeu se complique. Les optimisations
classiques sont rapidement insuffisantes pour des jeux classiques simples (puissance 4
1021 parties, reversi 1058 parties...), sans parler de jeux avec boucles (checs).
La solution la plus simple est de nexplorer les possibilits que jusqu une certaine profondeur n (autrement dit, de voir jusqu n coups). Cela implique de pouvoir donner un score
instantan une position autre que perdante ou gagnante (par exemple aux checs,
en fonctions des pices restant sur le jeu). Faire une bonne fonction dvaluation est
critique pour faire un bon joueur (pas facile aux checs, quasiment impossible au go).

Algorithmique et programmation (Licence 1 - S2)

39/39

S-ar putea să vă placă și