Logo Makeyourgame
Accueil Les formations Créer un jeu Les ateliers Les tutoriels Blog
Logo Makeyourgame
Les formations Les financements Les exercices La certification Unity
Logo Makeyourgame
Mes objectifs Les jeux Les ressources Le glossaire
Logo Makeyourgame
Les tutos Les tutos Youtube

C# : Les boucles : Langage C#

pictureProfil_cevantime
Ecrit par cevantime
Catégorie Langage C#
Mis à jour le 11/01/2020
C# : Les boucles

Dans un autre chapitre, nous avons vu les branchements conditionnels. Si ce concept permet déjà de faire beaucoup de choses en programmation, il en existe un autre, également très précieux : les boucles. Dans ce chapitre, nous allons voir ce que sont les boucles, leur fonctionnement, leurs possibilités. Allons-y !

20 min Débutant

Le concept de boucle

Dans la plupart des programmes, arrive un moment ou nous avons besoin de répéter une même action plusieurs fois à la suite. C'est même cette répétition d'action qui constitue la base de certains types de programme comme les jeux vidéos, par exemple. En effet, un jeu vidéo -croyez-le, ou non- est en fait un même code répété un très grand nombre de fois par seconde (idéalement 60 fois par seconde pour un 60 FPS). Ce code répété est ce qu'on appelle la boucle principale du jeu.

Naturellement, le jeu vidéo n'est pas le seul domaine de la programmation où les développeurs ont besoin de boucle : ce concept est omniprésent. Lorsque nous mettons au point des algorithmes c'est-à-dire des programmes permettant de calculer quelque chose, nous utilisons des codes qui se répéteront tant que le résultat n'a pas été trouvé. Un boucle pourra également servir à parcourir des ensembles d'éléments tels que des tableaux ou des listes.

Bien entendu, il s'agit rarement de répéter exactement le même code sinon l'intérêt serait limité. Pour exprimer toute leur puissance, les boucles doivent être utilisées conjointement aux branchements conditionnels pour permettre de créer des programmes réellement puissants et riches. Armés de ces deux possibilités, rien ne devrait plus résister à votre folie créative !

While : la boucle de base

Le bon nombre

Entrons dans le vif du sujet en étudiant notre première boucle : la boucle while. L'idée de cette boucle est la plus basique de toutes : exécuter du code tant que un certaine condition est vraie. C'est l'idée fondamentale qui se cache d'ailleurs derrière toutes les boucles. Voyons comment on la met en pratique en créant un nouveau programme nommé : BonNombre. Ce programme demandera à l'utilisateur quel est le sens de la vie. Tant que l'utilisateur ne lui aura pas donné la bonne réponse (qui, comme chacun le sait est le nombre 42), le programme continuera de lui poser la question.

Code préparatoire

Écrivons ensemble ce programme. Nous allons commencer par déclarer une variable contenant la réponse proposée par l'utilisateur. On initialise cette réponse à 0.

int reponse = 0;

Ensuite, nous allons créer un bloc de code à répéter tant que la réponse n'est pas 42. Pour cela, nous utiliserons une boucle while :

int reponse = 0;

while (reponse != 42)
{
    
}

Regardez attentivement le code ci-dessus. nous avons le mot clé while suivi d'un couple de parenthèses entourant un condition. Ce préambule est suivi d'un bloc de code (vide pour l'instant) entouré d'accolades. Cette syntaxe vous rappelle peut-être quelque chose. Eh oui, elle ressemble fort à celle du if.

int reponse = 0; 

if (reponse != 42) 
{ 
}

La différence est que le bloc de code qui suit un while ne doit pas s'exécuter si la condition est vraie mais tant que la condition est vraie. Autrement dit, le bloc de code entre les accolades se répètera jusqu'à ce que la variable reponse contienne la valeur 42. Remplissons ce bloc de code.

Fournir un code à répéter

La question à se poser est la suivante : que devons-nous faire tant que l'utilisateur n'a pas trouvé la réponse ? La réponse est très simple : lui poser, encore et toujours, la même question et lire sa réponse :

while (reponse != 42)
{
    Console.WriteLine("Quel est le sens de la vie ?");
    string reponseUtilisateur = Console.ReadLine();
}

Nous devons aussi convertir la réponse de l'utilisateur en entier et mettre cet entier dans la variable reponse afin de mettre à jour notre condition principale. Dans ce programme, nous utiliserons TryParse qui a la particularité de ne pas déclencher d'erreur si la valeur entrée par l'utilisateur n'est pas un entier:

while (reponse != 42)
{
    Console.WriteLine("Quel est le sens de la vie ?");
    string reponseUtilisateur = Console.ReadLine();
    Int32.TryParse(reponseUtilisateur, out reponse);
}

TryParse a un fonctionnement un peu particulier, il va mettre à jour la valeur de reponse (d'où le

out reponse

) si et seulement si reponse est un entier. Testons notre programme :

https://makeyourgame.fun/upload/uploads/2018/01/outrightnumber-300x39.png

Notre programme se répète tant que nous n'avons pas écrit 42.

Ça n'a l'air de rien, mais avec seulement cette boucle, nous venons d'entrer dans une autre dimension de la programmation. Nous pouvons d''ores et déjà faire à peu près tout. Les autres boucles que nous allons voir dans ce chapitre ne sont que des variantes un peu sophistiquées de while. Elles ne permettent pas de faire plus de choses, uniquement de les faire plus lisiblement.

La boucle do... while

Première variante de while : je vous présente do... while. Cette boucle permet d'exécuter le code à répéter au moins une fois. Elle ne vérifie la condition d'arrêt qu'après avoir exécuté son code. Voici comment on l'écrit :

do {
    // code à répéter
} while (condition);

Ici c'est le mot-clé do qui introduit le bloc de code à répéter. la condition n'est annoncée qu'à la fin du code par le mot-clé while. Réécrivons notre programme permettant de déterminer le sens de la vie en utilisant une boucle do... while.

static void Main(string[] args)
{
    int reponse = 0;
    do {
        Console.WriteLine("Quel est le sens de la vie ?");
        string reponseUtilisateur = Console.ReadLine();
        Int32.TryParse(reponseUtilisateur, out reponse);
    } while( reponse != 42);
}

Dans ce cas précis, la boucle do... while semble un peu plus adaptée que la boucle while. En effet, vu le fonctionnement de notre programme, il semble logique que notre code s'exécute au moins une fois. Il n'est pas non plus nécessaire de faire la vérification dès le début puisque c'est nous qui initialisons la variable reponse à 0 la première fois.

Néanmoins, cela ne veut pas dire que la boucle do... while est tout le temps plus adaptée que la boucle while. Ne décidez de la boucle à utiliser que lorsque vous savez exactement ce que vous voulez faire.

Cette remarque vaut aussi pour la boucle que nous allons voir maintenant : voici la boucle for !

La boucle for

La boucle for est elle aussi une variante de while même si elle s'écrit très différemment. Très utilisée, elle est particulièrement adaptée aux opérations de décompte et de parcours d'un ensemble d'éléments dont le taille peut varier au cours de l'exécution de la boucle.

Exemple de décompte : jouons à cache-cache

L'exemple de programme le plus simple du monde pour montrer ce que fait une boucle for : le programme qui joue à cache-cache. Ce programme vous propose de compter jusqu'à une certaine valeur, puis s'arrête de compter. Codons cela :

Code préparatoire

Initialisons un nouveau projet nommé CacheCache

D'abord, nous allons demander à l'utilisateur de choisir le nombre limite avant que l'ordinateur arrête de compter.

Console.Write("Jouons à cache cache ! Je dois compter jusqu'à combien ?");

int limite = Int32.Parse(Console.ReadLine());

Oups, j'ai utilisé ici un petit raccourci à la deuxième ligne. J'effectue la lecture de la réponse utilisateur et la conversion en entier dans la même ligne. Ne vous laissez pas intimider. Ce code est équivalent à :

Console.Write("Jouons à cache cache ! Je dois compter jusqu'à combien ?");

string reponseUtilisateur = Console.ReadLine();

int limite = Int32.Parse(reponseUtilisateur);

Dans ce dernier code, je passe par une variable intermédiaire. Dans le précédent, non. Aucune différence pratique. Choisissez celle que vous préférez.

Passons à la boucle en elle-même.

Syntaxe de la boucle for

for (int i = 1; i <= limite; i++)
{
    // placez ici le code à répéter
}

Quelle est cette syntaxe bizarre ? Rien de bien méchant, rassurez-vous. Ce code est strictement équivalent à :

int i = 1;

while( i <= limite)
{
    // placer ici le code à répéter
    i++;
}

Nous avons d'abord le mot-clé for qui annonce une boucle for. À l'intérieur des parenthèses, nous avons un code qui se décompose en trois parties séparées par des points virgule.

Nous avons d'abord le code d'initialisation qui permet de créer une variable incrémentielle i que nous ferons varier afin de la comparer à la variable limite choisie par l'utilisateur. Cette comparaison correspond à la condition de la deuxième partie. Enfin, nous avons en troisième partie le code à effectuer à la fin de la boucle. En l'occurrence, nous incrémentons i de façon à augmenter le décompte.

Comme on l'a vu, la boucle for peut s'écrire sous la forme d'une boucle while. Elle permet juste d'écrire la même chose d'une manière plus condensée et plus lisible.

Si l'usage de la boucle for est fréquent, elle n'est pas forcément adaptée à toutes les situations. On recommande cependant de l'utiliser dès que cela est pertinent car elle est plus facile à relire.

Le code final de notre cache cache peut ressembler à ceci :

Console.Write("Jouons à cache cache ! Je dois compter jusqu'à combien ? ");

int limite = Int32.Parse(Console.ReadLine());

for (int i = 1; i <= limite; i++)
{
    Console.WriteLine(i);
    Threading.Thread.Sleep(1000);
}

Console.WriteLine("J'arriiiiiiiive");

J'ai ajouté dans ma boucle une ligne permettant d'endormir le processus pendant 1 seconde (1000 millisecondes) afin de marquer une pause entre chaque décompte.

https://makeyourgame.fun/upload/uploads/2018/01/outcachecache-300x48.png

La boucle foreach

Quatrième et dernière boucle que je vous présente : la boucle foreach. Il s'agit d'une variante de la boucle for. Celle-ci permet de parcourir un ensemble d'éléments dont la taille ne change pas au cours de la boucle.

Les mousquetaires

Pour l'illustrer, nous allons simplement créer un petit programme console appelé Mousquetaires. Ce programme vous propose d'afficher la liste de nos mousquetaires préférés.

Commençons par créer un tableau contenant la liste de nos mousquetaires :

string[] tableauMousquetaires = { "Athos", "Porthos", "Aramis" };

mousquetaires est un tableau de chaines de caractères, c'est-à-dire un ensemble fini et délimité de valeurs de type string.

Parcourir notre tableau

Maintenant, nous allons déclarer notre boucle foreach afin de parcourir ce tableau. Voici la syntaxe :

foreach (string mousquetaire in tableauMousquetaires)
{
    // faire quelque chose de mon mousquetaire
}

La syntaxe de foreach est assez simple mais il convient de bien en comprendre le principe. Nous avons d'abord le mot-clé foreach qui permet bien entendu d'annoncer une boucle foreach. Ensuite, à l'intérieur des parenthèses, nous avons une sorte de déclaration de variable. Nous déclarons la variable mousquetaire qui sera extraite du tableau de mousquetaires tableauMousquetaires grâce au mot-clé in. La variable mousquetaire prendra successivement les valeurs de chacun des éléments du tableau, c'est-à-dire le nom de chacun des mousquetaires. Comme notre tableau est un tableau de string (chaines de caractères), chacun des mousquetaire sera de type string. mousquetaire est donc de type string.

Le bloc de code suivant le foreach sera donc répété autant de fois qu'il y a de mousquetaires dans mon tableau. En l'occurrence, 3 fois.

Dans ce programme, nous nous contenterons d'afficher le nom du mousquetaire, précédé d'un tiret. Cela nous donne :

string[] tableauMousquetaires = { "Athos", "Porthos", "Aramis" };

foreach (string mousquetaire in tableauMousquetaires)
{
    Console.WriteLine(" - " + mousquetaire);
}

Notez que nous utilisons ici la concaténation de chaines de caractères afin d'ajouter un tiret devant le nom du mousquetaire. On obtient :

https://makeyourgame.fun/upload/uploads/2018/01/outmousqueteers-300x23.png

La boucle foreach a une syntaxe très simple mais n'est adaptée qu'au parcours d'un ensemble d'éléments dont la taille ne varie pas au cours de l'exécution de la boucle. Dans les autres cas, on lui préfèrera une boucle for ou encore while. Cependant, je vous conseille de l'utiliser chaque fois que c'est possible pour des raisons de lisibilité et d'efficacité.

Contrôler sa boucle : break et continue

Il est possible d'accentuer son contrôle sur une boucle. Dans cette dernière partie, nous verrons ce que sont les mot-clé break et continue qui nous permettent de mieux contrôler notre boucle.

break : sortir de la boucle

Chercher l'intrus

Il est possible d'interrompre le fonctionnement d'une boucle en utilisant le mot-clé break. Ce mot clé est assez utile en algorithmique lorsque l'on a obtenu le résultat qu'on voulait dans notre boucle est qu'on n'a pas besoin que celle-ci continue de s'exécuter. Pour vous montrer son usage, nous allons créer un petit programme console appelé ChercherLIntrus.

Dans ce programme, un tableau est considéré comme valide si il ne contient que des nombres positifs. Le programme devra détecter si un tableau est valide ou invalide.

Par exemple : le tableau { 99, 8, 64, 109 } est valide car il ne contient que des nombres entiers positif. Le programme devra donc afficher "Tableau valide !". En revanche, si le tableau est { 55, -1, 2, -6 }, le programme devra afficher "Tableau invalide !" car il contient des valeurs négatives.

Vous pouvez déjà écrire un programme de ce genre sans utiliser break mais vous allez voir que le programme est plus économe en temps d'exécution si vous l'utilisez. Essayons de nous en passer :

int[] tableauEntiers = { 1, -50, 33, 4 };

bool valide = true;

foreach (int entier in tableauEntiers)
{
    Console.WriteLine("On teste la valeur " + entier);
    
    if (entier < 0)
    {
        valide = false;
    }
}

if (valide)
{
    Console.WriteLine("Le tableau est valide");
}
else
{
    Console.WriteLine("Le tableau est invalide");
}

Que fait ce programme ? Il déclare d'abord un tableau d'entiers. Ensuite, il déclare un booléen valide afin de stocker la condition : le tableau est valide. On parcourt ensuite le tableau au moyen d'une boucle foreach.

Si, dans ce tableau, on trouve une valeur négative, on dit que la condition valide est fausse puisque le tableau ne peut contenir que des valeurs positives.

À la fin du parcours, on écrit "Le tableau est valide" si valide est vrai, "Le tableau est invalide" sinon.

Vous voyez que ce programme est un peu plus complexe que les précédents car il combine les boucles et les branchements conditionnels. Il est très important que vous essayiez de le comprendre à fond.

Voyons ce qu'il donne à l'exécution :

https://makeyourgame.fun/upload/uploads/2018/01/outintrude-300x34.png

 

Optimiser avec break

Comme attendu, notre code parcourt toutes les valeurs du tableau et finit par donner son verdict. Notre code fonctionne donc bel et bien. Cependant, celui-ci n'est pas optimisé. Pour une raison simple : il pourrait s'arrêter dès qu'il a trouvé la première valeur négative, en l'occurrence -50. En effet, il est inutile qu'il continue son parcours étant donné qu'il n'y a aucune chance que notre tableau redevienne valide en cours de route : en gros, dès que la valeur fautive est trouvée, c'est foutu, pas la peine d'aller plus loin.

Pour exprimer cette notion de "Pas la peine d'aller plus loin", on utilise le mot-clé break dont l'effet va être d'arrêter la boucle. Voyez plutôt.

int[] tableauEntiers = { 1, -50, 33, 4 };

bool valide = true;

foreach (int entier in tableauEntiers)
{
    Console.WriteLine("On teste la valeur " + entier);
    
    if (entier < 0)
    {
        valide = false;
        break; // interrompt la boucle
    }
}

if (valide)
{
    Console.WriteLine("Le tableau est valide");
}
else
{
    Console.WriteLine("Le tableau est invalide");
}

Qui donne :

https://makeyourgame.fun/upload/uploads/2018/01/outintruderbreak-300x23.png

Vous voyez que grâce à break, on épargne à notre programme des opérations inutiles. Vous pensez peut-être que cela n'a pas d'importance étant donné la rapidité des ordinateurs actuels. Néanmoins, souvenez-vous que ce genre d'optimisation peuvent avoir une impact conséquent pour des applications dans lesquelles les performances ont une importance capitale. Comme par exemple... les jeux vidéos !

continue : zapper la suite

Autre mot-clé important quand on gère des boucles : continue. Contrairement, à break, il ne permet pas de sortir de la boucle mais seulement de zapper une seule fois la suite du code de la boucle.

Pour illustrer le comportement de continue, nous allons créer un programme appelé NombresPairs. Ce programme affichera tous les entiers pairs d'un tableau d'entiers.

Voici :

int[] tableauEntiers = { 4, 5, 8, 11, 19, 22 };

foreach (int entier in tableauEntiers)
{
    if (entier % 2 == 1) // entier est-il impair ?
    {
        continue;
    }
    Console.WriteLine(entier);
}

Qui donne :

https://makeyourgame.fun/upload/uploads/2018/01/outpair-300x25.png

Ce programme vérifie pour chaque entier du tableau si il est impair, autrement dit si le reste de la division euclidienne de l'entier en question et de 2 est 1 (3 est impair car 3 % 2  égale 1). Si tel est le cas, le reste du bloc de code est zappé (non exécuté). Cependant, la boucle continue, contrairement à break.

L'intérêt du mot-clé continue est moins évident que celui de break. Cependant, vous aurez probablement à l'utiliser de temps en temps pour rendre votre boucle plus lisible est éviter la duplication de code.

Conclusion

Les boucles ne sont pas la notion la plus évidente à acquérir en informatique. Cependant, une fois acquises, vous êtes armés pour mettre au point des programmes complexes et complets. Je vous encourage à vous exercer en vous essayant aux exercices de la plateforme.

Vues: 5530

Licence:



Validation du Tutoriel

Veuillez vous connecter ou créer un compte pour pouvoir valider ce tutoriel et ainsi gagner de l'expérience (XP) !