Développement C# (.NET)

Développement C# (.NET)

Mis à jour le mardi 8 janvier 2013
Notions fondamentales

Un peu d'algorithmique

Maintenant que nous avons vu les types de données et les opérations élémentaires en C# nous allons traiter tout ce qui concerne les boucles et les conditions. Pour cela, vous allez pleinement réinvestir ce que nous avons vu précédemment sur les opérateurs logiques.

Les conditions

Une condition simple: SI...

Lorsque l'on réalise un programme informatique, on a très souvent besoin d'exprimer une condition, c'est à dire faire une action seulement dans certain cas. Par exemple "si ton age est plus petit que 18 alors tu es mineur".

Dans le code on va pouvoir faire même genre de structure, avec le mot-clé if (signifiant "si" en langue anglaise).

Le but est de tester certaines valeurs, qui sont bien évidemment stockées dans des variables, et d'exécuter une suite d'instruction seulement dans le cas où la condition est vraie (c'est à dire qu'elle renvoie un booléen true).

Sans plus attendre voici le squelette de code minimal d'une condition if simple ainsi qu'un exemple d'utilisation :

if( /* expression booléenne */ ) 
{
// Le code présent ici n'est exécuté que si l'expression booléenne renvoie true
}

// Le code juste après ce commentaire est exécuté dans tout les cas.
int age = 17;

if(age >= 18)
{
   Console.WriteLine("Tu es majeur.");
}

Essayez ce code, puis réessayez en mettant la variable age à 19.

Dans nos tests nous pouvons utiliser tout ce que nous avons vu jusqu'à présent dans ce chapitre : l'égalité et les comparaisons ainsi que les opérations et et ou.

Ce dernier code est bien beau! Mais si la personne est mineure, je doit ré-utiliser un test if ?

On pourrait :) Mais ce n'est pas ce qu'on fait la plupart du temps. On va voir cela dans un instant ;)

Des traitements alternatifs : SI... SINON...

Tout à l'heure, pour effectuer un traitement lorsque la personne est majeure, et un autre traitement lorsqu'elle est mineure, nous aurions pu faire ainsi :

int age = 17;

if(age >= 18)
{
   Console.WriteLine("Tu es majeur.");
}

if(age < 18)
{
   Console.WriteLine("Tu es mineur.");
}

Ce code fonctionnera, mais il manque d'optimisation et de logique!! En effet, si la personne est majeure, la première condition sera remplie alors que la seconde ne le sera jamais, mais le programme vérifiera tout de même si la seconde est aussi remplie!
Il est en plus plus difficilement modifiable : pour modifier la limite d'âge vous allez devoir modifier le code en deux endroits, ce qui augmente le nombres d'erreurs que l'on peut faire (et ce genre de petite erreur est très difficile à voir sans prendre un peu de recul sur son code).

Heureusement, il y existe une manière bien plus élégante d'opérer. Nous allons pouvoir implémenter la structure algorithmique "si... sinon...", puisque le "si" est traduit en C# par if (traduction anglaise de "si"), le "sinon" sera traduit par... "else" ("sinon" en anglais). Ce qui nous donnera le structure suivante :

if(booleen)
{
   //Mettez ici ce que vous avez à faire lorsque la condition est remplie
}
else
{
   //Mettez ici ce que vous avez à faire lorsque la condition n'est pas remplie
}

Transposé au cas de la vérification de l'âge de la personne, nous aurons le code suivant :

int age = 17;
if (age >= 18)
    Console.WriteLine("Vous êtes majeurs");
else
    Console.WriteLine("Vous êtes mineurs");

Des conditions complètes : SI ...SINON SI .... [SINON SI]...SINON

Si nos vérifications se complexifient, nous pouvons appliquer la structure algorithmique suivante "SI...SINON SI... SINON...", en ajoutant autant de "SINON SI..." que nous le voulons en veillant bien de les mettre avant le "SINON..." final.

Prenons l'exemple de grandes multinationales comme une chaine de grandes surfaces et une société ferroviaire qui sont partenaires, nous pouvons avoir des réductions chez la société ferroviaire grâce à la carte de la grande surface, nous pourrions avoir par exemple dans la billetterie automatique le code suivant.

bool aLaCarteTrain;
bool aUneCarteGrandeSurfacePartenaire;
int tarif;
// Des instructions doivent être ajoutées ici pour assigner une valeur
// aux variables
if (aLaCarteTrain) //S'il a la carte
{
    Console.WriteLine("Vous devez payer : " + (tarif*0.5).ToString());
}

else if (aUneCarteGrandeSurfacePartenaire)//S'il a une carte d'un partenaire
{
    Console.WriteLine("Vous devez payer : " + (tarif * 0.75).ToString());
}

else//S'il n'a aucune carte de fidélité
{
    Console.WriteLine("Vous devez payer : " + tarif.ToString());
}
Console.ReadKey(true);

Une alternative pratique : le switch

Lorsque l'on enchaine plusieurs "else if" et si les vérifications portent sur une même variables, il peut être pratique d'utiliser un "switch" qui a une logique plus appropriée, par exemple au lieu de faire ça :

SI variable == "valeur1"
ALORS //Action 1
SINON SI variable == "valeur2"
ALORS //Action 2
SINON SI variable == "valeur3"
ALORS //Action 3
SINON SI variable == "valeur4"
ALORS //Action 4
SINON //Action 5

nous ferrons :

VERIFIER variable
CAS valeur1: //Action 1
CAS valeur2: //Action 2
CAS valeur3: //Action 3
CAS valeur4: //Action 4
SINON  //Action 5

La syntaxe en exemple est la suivante :

string couleur = "rouge";

switch (couleur)
{
    case "rouge":
        Console.WriteLine("Tu aimes la couleur du sang");
        break;

    case "vert":
        Console.WriteLine("Tu aimes la nature");
        break;

    case "bleu":
        Console.WriteLine("Tu aimes la couleur du ciel");
        break;

    case "blanc":
        Console.WriteLine("Tu aimes la purete");
        break;

    default:
        Console.WriteLine("Je n'ai aucune commentaire a faire");
        break;
}

Nous spécifions dans les parenthèses suivants le mot clés "switch" la variable sur laquelle la vérifications porte. Ensuite, nous mettons le mot clé "case" suivi de la valeur à vérifier suivi des deux points, des actions à effectuer puis le mot clés "break". Ce mot clé break permettra de sortir du switch si un "case" est vérifié (ça ne sert alors à rien de continuer à vérifier, "couleur" ne peux pas avoir deux valeurs en même temps :p )

Un raccourci pour if...else... : l'opérateur ternaire

Précédemment nous avons vu des opérateur binaires comme "==" ou "+" et des opérateurs unaires comme "!" (not), sachez qu'il existe aussi un opérateur ternaire (qui s'applique sur trois opérandes!!). On l'appelle "opérateur" (au singulier) mais c'est plutôt deux opérateurs fonctionnant ensembles : "?" et ":". Il va nous servir à écrire de manière très condensée un if...else... simple, imaginez le code de manière suivant :

string texte;
bool unBooleen = true;

if (unBooleen)
    texte = "c'est vrai";
else
    texte = "c'est faux";

Ce code est plutôt court, mais il fait un peu long pour ce que nous voulions faire : assigner une chaine de caractères en fonction de la valeur de vérité d'un booléen ou d'une expression booléenne. Il n'y a en aucun cas des instructions plus complètes après le "if(...)" ni après le "else", dans ce cas, nous utiliserons la syntaxe suivante :

[type] mavariable = expressionBooleenne ? valeurSiVrai : valeurSiFaux ;

Ce qui donnera pour notre exemple précédant:

string texte;
bool unBooleen = true;
texte = unBooleen ? "C'est vrai" : "C'est faux";

On ne gagne "que" trois lignes de codes, mais sachez qu'il arrive de manière plutôt courante d'avoir à faire des assignations conditionnelles comme celle-ci avec des nombreuses variables l'une à la suite de l'autre, et ce raccourci d'écriture permet de gagner en lisibilité pour celui qui est à l'aise avec les opérateurs ternaires.

Je vous ai montré cet opérateur en dernier étant donné qu'on peut s'en passer et que tout le monde n'a pas la même aisance pour l'utiliser et le lire, sachez donc que je ne vous en voudrais pas si vous ne l'utilisez pas tout les jours ;) .

Mais trêve de bavardage, le chapitres est bientôt terminé, mais il nous reste encore à voir quelque chose d'essentiel dans n'importe quel langage : les boucles !

Les boucles

Maintenant que nous savons exécuter des instructions de manière conditionnelle, il pourrait être intéressant de répéter, toujours de manière conditionnelle une instruction. L'idée de base serait de exécuter une instruction déjà exécuté auparavant, autrement dit "remonter" dans notre code, pour cela, C# nous donne le mot clé goto qui s'utilisera de la manière suivante:

using System;

namespace Formation
{
    static class Program
    {
        static void Main()
        {
            string motDePasse = "";//On crée une variable "motDePasse"

        Debut://On crée un "label", il permet d'identifier un endroit dans le code
            motDePasse = Console.ReadLine();//On demande à l'utilisateur de rentrer le mot de passe

            if (motDePasse != "P4ssw0rD")//Si le mot de passe n'est pas bon
            {
                Console.WriteLine("Ce n'est pas le bon mot de passe, retentez");
                goto Debut;//Avec le mot clé "goto" on revient à l'endroit identifié tout à l'heure
            }

        }
    }
}

Ce code fonctionnera, mais presque tout le développeurs vous diront que les "goto", c'est mal. Même si ils sont pratiques, ils rendent vite le code illisible, à exécuter le code dans n'importe quel sens, il devient vite très brouillons.

Heureusement, il existe une manière beaucoup plus élégante, et surtout plus lisible d'exécuter plusieurs fois le même code de manière conditionnelle : les boucles!! En C# il existe plusieurs types de boucles, nous allons les voir l'une après l'autre.

Une boucle simple: "while"

La boucle "while" est l'application de la structure algorithmique "TANT QUE", ce qui nous donnera en algorithmique:

TANT QUE conditionRemplie
FAIRE ...
FIN TANT QUE

Et en C# :

while(expressionBooleenne)
{
   //code à exécuter
}

Comme vous le voyez, la syntaxe est plutôt simple, un place une expression booléenne entre les parenthèses suivant le mot-clé "while". Ensuite dans les accolades, nous mettrons le code à exécuter. Pour l'exemple du mot de passe que nous avons fait tout à l'heure avec avec "goto" :-° nous aurons :

string motDePasse = Console.ReadLine();

while (motDePasse != "P4ssw0rD")
{
    Console.WriteLine("Ce n'est pas le bon mot de passe, retentez");
    motDePasse = Console.ReadLine();
}

Nous pouvons bien sûr placer le code que nous voulons entre les accolades, même d'autres boucles!!

La syntaxe de la boucle "while" est simple, mais parfois elle se trouve moins adaptée, heureusement d'autres types de boucles existent.

Un nombre précis d'itérations : "for"

La boucle for va être l'application de la structure algorithmique "POUR...", ce qui nous donnera en algorithmique:

POUR ENTIER monEntier DE ... A ...
FAIRE...
FIN POUR

Et en C#:

for(int i = valeurDepart; i < valeurDeFin ; i++)
{
   //Code à exécuter
}

La syntaxe est un peu plus complexe, la boucle for a besoin de trois informations : une initialisation, une condition et une opération (généralement une incrémentation, mais pas tout le temps).

Pour notre exemple concret, nous allons revenir au primaire, quand notre maitresse nous donnait des lignes d'écriture :ange: , en fait, avec du C# c'est beaucoup moins fatiguant :p :

Console.WriteLine("Tapez (une seule fois :) ) la ligne à écrire");
string ligne = Console.ReadLine();//On entre la ligne à écrire
Console.WriteLine("Tapez le nombre de ligne que vous devez écrire");
int nombre = int.Parse(Console.ReadLine());//On entre le nombre de ligne à entrer
for (int i = 0; i < nombre; i++)//On boucle autant de fois que l'on a spécifié dans "nombre"
{
    Console.WriteLine(ligne);
}

Si nous voulons écrire 5 fois "Je ne frappe pas mes camarades", la sortie sera celle-ci:

Tapez (une seule fois :) ) la ligne à écrire
Je ne frappe pas mes camarades
Tapez le nombre de ligne que vous devez écrire
5
Je ne frappe pas mes camarades
Je ne frappe pas mes camarades
Je ne frappe pas mes camarades
Je ne frappe pas mes camarades
Je ne frappe pas mes camarades

Nous pouvons faire mieux en ajoutant devant chaque ligne son numéro avec le code suivant :

Console.WriteLine("Tapez (une seule fois :) ) la ligne à écrire");
string ligne = Console.ReadLine();
Console.WriteLine("Tapez le nombre de ligne que vous devez écrire");
int nombre = int.Parse(Console.ReadLine());
for (int i = 0; i < nombre; i++)
{
    Console.WriteLine((i+1).ToString() + " : " + ligne); //Seule cette ligne a été modifiée
}

Le code n'est pas beaucoup plus complexe, nous récupérons juste l'entier "i" qui changera de valeur à chaque itération et nous plaçons sa valeur (plus un) devant chaque ligne, ce qui vas nous donner:

Tapez (une seule fois :) ) la ligne à écrire
Je ne frappe pas mes camarades
Tapez le nombre de ligne que vous devez écrire
5
1 : Je ne frappe pas mes camarades
2 : Je ne frappe pas mes camarades
3 : Je ne frappe pas mes camarades
4 : Je ne frappe pas mes camarades
5 : Je ne frappe pas mes camarades

Un boucle while particulière : do...while

La boucle do...while est l'application de la structure algorithmique "FAIRE ...TANT QUE" qui permet de boucler en vérifiant si l'on doit boucler à nouveau après l'exécution de l'itération. En algorithmique cela nous donnera:

FAIRE
...
TANT QUE conditionRemplie

Et en C#:

do
{
//Code à exécuter
}while(expressionBooleene);

L'utilisation de cette boucle va être quasiment similaire à la boucle while simple, la principale différence est qu'avec do...while, la ou les instructions à l'intérieur de la boucle vont être exécutées au moins une fois !. Une exemple simple peut être quand on nous demande de faire quelque chose, et de recommencer tant que c'est pas bon, on ne peut pas bien faire avant d'avoir fait :p , il faudra donc exécuter l'intérieur de la boucle au moins une fois.
Dans ce cas, notre exemple du mot de passe de tout à l'heure serait bien mieux avec une boucle do...while plutôt que while :

string motDePasse;
do
{
    Console.WriteLine("Ce n'est pas le bon mot de passe, retentez");
    motDePasse = Console.ReadLine();
} while (motDePasse != "P4ssw0rD");
Console.WriteLine("Bravo vous avez trouvé!!");

Ceci boucle la partie sur les boucles (c'est le cas de le dire :p ) nous allons à présent voir en quoi d'autre les boucles peuvent être très utiles.

Boucles et conditions : cas pratiques

Pour plus de clarté, je recommande de supprimer la ligne using System.Linq; car cet espace de nom contiens beaucoup de méthodes utilisées avec les tableaux, mais ses méthodes sont apparues "après" les débuts des tableaux en C#, nous nous attacherons ici juste à une utilisation simple des tableaux et ces méthodes prennent beaucoup de places dans la fenêtre de l'auto-complétion :p

Tableau simple

Création

Une des utilisations principales des boucles for va être de parcourir des tableaux de données. Un tableau va nous servir à stocker plusieurs valeurs de même types ensembles. Pour déclarer un tableau la syntaxe va être la suivante:

type[] monTableau = new type[taille];

Par exemple pour tableau contenant 42 int:

int[] tableauDeInt = new int[42];

Pour placer un élément dans ce tableau, il n'y a qu'à spécifier l'index entre crochets ( '[' et ']' ) et à faire une simple assignation, par exemple pour mettre la valeur 12 dans la première case du tableau nous ferrons :

int[] tab = new int[42];
tab[0] = 12;

Il est aussi possible de déclarer une tableau sans le mot clé new et sans lui donner sa taille, pour cela, on lui donne directement ses différentes valeurs entre accolades, chaque valeur étant séparée par une virgule:

int[] tab = { 1, 5, 2, 5, 90, 42, 17 };

Si vous voulez connaitre la taille d'un tableau simple, vous avez une propriété Lenght sur votre tableau. Le Console.WriteLine(...) nous affichera ici la taille du tableau..

int[] tab = new int[42];//On déclare un tableau de 42 "cases"
Console.WriteLine("La réponse est " + tab.Length);//Affichera "La réponse est 42"
Parcourir un tableau simple

Vous pouvez déjà deviner comment nous allons parcourir notre tableau (et aussi car je vous l'ai dit plus haut :p ) : une boucle for en utilisation la propriété Length !!

Dans le petit exemple qui suit, nous allons afficher pour chaque élément du tableau son index et sa valeur:

int[] tab = { 1, 5, 2, 5, 90, 42, 17 };
for (int i = 0; i < tab.Length; i++)
{
    Console.WriteLine("Index " + i + " valeur : " + tab[i]);
}

Retenez bien cette utilisation de i qui nous permet de parcourir chaque élément du tableau, ce système de parcours de tableau n'est pas seulement propre au C#, il est très courant dans beaucoup de langages.

Ce code nous affichera :

Index 0 valeur : 1
Index 1 valeur : 5
Index 2 valeur : 2
Index 3 valeur : 5
Index 4 valeur : 90
Index 5 valeur : 42
Index 6 valeur : 17
Press any key to continue . . .
Une boucle plus simple pour parcourir les tableaux : foreach

Lorsque vous avez juste besoin d'accéder à l'élément du tableau et que vous vous en moquez d'avoir l'index, il existe une boucle très pratique : foreach. Comme son nom peut l'indiquer, elle va effectuer un traitement pour chaque élément d'une collection ou d'un tableau. L'utilisation est très simple, par exemple pour notre tableau de tout à l'heure :

int[] tab = { 1, 5, 2, 5, 90, 42, 17 };
foreach (int item in tab)
{
    Console.WriteLine(item);
}

Décomposons un peu la première ligne:

  • Le mot clé foreach

  • Le type d'élément dans la collection, si vous ne savez pas le type, vous pouvez utiliser le mot clé "var" à la place, ce sera toujours du typage statique, ce sera le compilateur qui va trouver implicitement le type (un élément d'un tableau de int sera forcément un int)

  • Le nom qu'on va donner à l'élément en cours de manipulation, ici je l'appelle "item"

  • Mot clé in, c'est assez verbeux mais ça permet de comprendre facilement le sens du foreach

  • Et finalement le nom du tableau à parcourir

La première fois que j'ai vu ce type de boucle, j'ai été déstabilisé par le fait que chaque élément du tableau portait le même nom quand on le manipulait, mais par le suite je me suis dit qu'en réalité, chaque élément est manipulé l'un après l'autre et pour m'aider, je donnais toujours comme nom: elementEnTrainDEtreManipule ainsi cela m'aidait à comprendre que je ne manipulais qu'un seul élément à la fois et que quand j'avais fini avec un élément, il n'avait plus besoin d'être "en cours de manipulation" et donc je passais au suivant qui était à son tour "en cours de manipulation".

Les tableaux à plusieurs dimensions

Création

Il est aussi possible de faire des tableaux à plus d'une dimensions, par exemple si vous voulez représenter un jeu d'échec, il vous faudra un tableau à deux dimensions de 8 sur 8. Pour le déclarer et l'instancier, la syntaxe n'est guère plus compliquée :

int[,] echiquier = new int[8,8];

Nous remarquons seulement la virgule entre les crochets pour la partie déclaration, cela signifie que nous aurons ici deux dimensions. Et lors de l'instanciation, nous plaçons la taille des deux dimensions séparées par une virgule.
Il est bien sur possible de créer des tableaux à autant de dimensions que l'on veut, par exemple pour l'évolution de l'état de plusieurs échiquiers au cours du temps:

static void Main(string[] args)
{
    int tailleEchiquier = 8;
    int nombreEchiquier = 4;
    int nombreDeParties = 10;
    int[,,,] echiquier = new int[nombreDeParties,nombreEchiquier,tailleEchiquier,tailleEchiquier];
}

Il suffit de placer dans la partie déclaration le bon nombre de virgules (nombre de dimensions - 1) et de donner le bon nombre de taille des dimensions.

Pour déclarer le tableau de manière implicite, il nous faut imaginer que nous créons un tableau dans chaque case d'un autre tableau :

int[,] tableau = { { 10, 8, 4, 5 }, { 7, 4, 3, 7 }, { 6, 54, 32, 42 } };

Ici nous avons trois tableaux de quatre éléments dans un autre tableau.

Parcourir un tableau à plusieurs dimensions

Pour parcourir ce tableau, plusieurs choix s'offrent à nous : la boucle foreach et l'imbrication de boucles for.
Pour la boucle foreach, absolument rien ne change:

static void Main(string[] args)
{
    int[,] tableau = { { 10, 8, 4, 5 }, { 7, 4, 3, 7 }, { 6, 54, 32, 42 } };

    foreach (var item in tableau)
    {
        Console.WriteLine(item);
    }
}

Ici chaque élément élément va être affiché comme si nous avions un long tableau à une seule dimension (avec les différentes lignes mises bout à bout).

Mais généralement, lorsqu'on crée un tableau à plusieurs dimensions c'est pour accéder "manuellement" à une certaine valeur et faire interagir certaines cases entre elles de manière plus complexe (en effet, il sera impossible avec un foreach d'afficher un échiquier étant donné que nous ne détectons pas le changement de ligne.

Pour cela, nous allons donc utiliser des boucles imbriquées pour traiter chaque ligne indépendamment. Dans l'exemple suivant je crée un tableau de 8 cases sur 8, la valeur de chaque case est 0 (valeur par défaut de int). Et ensuite j'utilise deux boucles imbriquées pour parcourir d'abord chaque ligne et pour chacune de ces lignes, je parcours chaque case:

static void Main(string[] args)
{
    int[,] echiquier = new int[8, 8];

    for (int i = 0; i < echiquier.GetLength(0); i++)
    {
        Console.Write("|");
        for (int j = 0; j < echiquier.GetLength(1); j++)
        {
            Console.Write(echiquier[i, j] + "|");
        }
        Console.WriteLine();
    }
}

Ce qui va afficher:

|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
|0|0|0|0|0|0|0|0|
Press any key to continue . . .

Bon, ce n'est pas encore au maximum du potentiel graphique de votre ordinateur mais on a déjà une représentation de échiquier en deux dimensions (ce qui n'était pas le cas avec le foreach)
Remarquez bien l'utilisation de i et j qui nous permettent d'accéder successivement à chaque case du tableau.

Pour rester simple, je suis resté sur un tableau avec "seulement" deux dimensions, mais avec plus de dimensions le principe serait resté le même, il suffit d'avoir autant de boucles imbriquées que de dimensions.

Exercices pratiques

Maintenant c'est à vous de pratiquer!! Je vais vous donner quelques petits exercices puis les corrections que je propose.

Les exercices

Amélioration de l'algorithme du mot de passe - 1

Nous allons reprendre un des codes présents dans ce cours, celui avec la boucle do...while vérifiant un mot de passe. Ce code était le suivant :

string motDePasse;
do
{
    Console.WriteLine("Ce n'est pas le bon mot de passe, retentez");
    motDePasse = Console.ReadLine();
} while (motDePasse != "P4ssw0rD");
Console.WriteLine("Bravo vous avez trouvé!!");

Une première amélioration serait de ne pas se fixer seulement au mot de passe, mais aussi au nom d'utilisateur. Améliorez donc le code précédent pour vérifier le nom d'utilisateur puis le mot de passe. Pour cela, il vous faudra ajouter une variable et utiliser à bon escient les opérateurs logiques.

Amélioration de l'algorithme du mot de passe - 2

Ensuite, maintenant que nous demandons le login et le de passe, il nous faut aider un peu l'utilisateur en lui disant lorsqu'il se trompe s'il s'est trompé sur le login ou sur le mot de passe. Nous veillerons à n'afficher l'alerte du mot de passe uniquement si le login est bon.
Là, plusieurs choix peuvent s'offrir à vous, vous pouvez utiliser ou non une variable supplémentaire de type booléen (je vous laisse découvrir son utilité. ;) ) Et en fonction de la présence ou non de ce booléen, vous pouvez avoir une disposition plus ou moins différente des conditions.

Amélioration de l'algorithme du mot de passe - 3

C'est bien de demander le login et mot de passe tant que l'on a pas trouvé et de dire si c'est le login ou le mot de passe qui n'est pas bon mais cela manque un peu de sécurité si quelqu'un utilise la force brute (c'est à dire s'il utilise toute les combinaisons possibles et imaginables). Nous allons donc implémenter un compteur qui empêchera de se tromper plus de deux fois (comme pour utiliser une carte de crédit). Là il vous faudra bien entendu une variable supplémentaire d'un type numérique (n'importe quel type entier ira très bien).

Correction

Amélioration de l'algorithme du mot de passe - 1

Par rapport au code de l'énoncé, j'ai ajouté une variable de type string pour contenir le login que je déclare en même temps que le mot de passe.
Ensuite dans la boucle, j'affiche un message supplémentaire pour demander le login puis j'utilise Console.ReadLine() pour demander ce login, de la même manière que ce qui a été fait avec le mot de passe.

Et enfin en plus de demander de boucler si le mot de passe est différent, je demande aussi de boucler si le login est différent. J'utilise le OU logique car il suffit que l'un des deux soit incorrect pour devoir redemander le tout.

string login, motDePasse;
do
{
    Console.WriteLine("Le couple login - mot de passe n'est pas bon");
    Console.Write("Tapez votre login: ");
    login = Console.ReadLine();
    Console.Write("Tapez votre mot de passe: ");
    motDePasse = Console.ReadLine();
} while (login != "zozor" || motDePasse != "P4ssw0rD");
Console.WriteLine("Bravo vous avez trouvé!!");
Amélioration de l'algorithme du mot de passe - 2

Comme je vous ai dit que plusieurs choix s'offraient à vous, je vais vous proposer plusieurs corrections, il n'y en a pas forcément une meilleure qu'une autre, l'optimisation de chacune est à peu près équivalente.
Tout d'abord, sans utiliser de booléen supplémentaire et en imbriquant les conditions (pour éviter de recopier les chaines de caractère correspondant au login et mot de passe, j'ai crée deux variables supplémentaires en début de programme) :

string loginATrouver = "zozor", motDePasseATrouver = "P4ssw0rD";
string login, motDePasse;
do
{
    Console.Write("Tapez votre login: ");
    login = Console.ReadLine();
    Console.Write("Tapez votre mot de passe: ");
    motDePasse = Console.ReadLine();
    if (login == loginATrouver)
    {
        if (motDePasse != motDePasseATrouver)
        {
            Console.WriteLine("Le mot de passe est incorrect");
        }
    }
    else
    {
        Console.WriteLine("Le login est incorrect");
    }
} while (login != loginATrouver || motDePasse != motDePasseATrouver);
Console.WriteLine("Bravo vous avez trouvé!!");

Puis si nous ne voulons pas imbriquer les conditions, nous pouvons utiliser un booléen supplémentaire:

string loginATrouver = "zozor", motDePasseATrouver = "P4ssw0rD";
string login, motDePasse;
do
{
    bool loginCorrect = false;
    Console.Write("Tapez votre login: ");
    login = Console.ReadLine();
    Console.Write("Tapez votre mot de passe: ");
    motDePasse = Console.ReadLine();
    if (login == loginATrouver)
    {
        loginCorrect = true;
    }
    else
    {
        Console.WriteLine("Le login est incorrect");
    }
    if (loginCorrect && motDePasseATrouver != motDePasse)
    {
        Console.WriteLine("Le mot de passe est incorrect");
    }
} while (login != loginATrouver || motDePasse != motDePasseATrouver);
Console.WriteLine("Bravo vous avez trouvé!!");

Et pour finir, nous pouvons utiliser la structure algorithmique "SI....SINON SI...SINON" si on ne veut pas utiliser de booléen supplémentaire. Remarquez que dans l'expression du "else if", je ne vérifie pas si le mot de passe est bon, puis si cette expression est évaluée, c'est que l'expression du "if" était forcément fausse, donc que le mot de passe était correct. :soleil:

string loginATrouver = "zozor", motDePasseATrouver = "P4ssw0rD";
string login, motDePasse;
do
{
    Console.Write("Tapez votre login: ");
    login = Console.ReadLine();
    Console.Write("Tapez votre mot de passe: ");
    motDePasse = Console.ReadLine();
    if (login != loginATrouver)
    {
        Console.WriteLine("Le login est incorrect");
    }
    else if (motDePasseATrouver != motDePasse)
    {
        Console.WriteLine("Le mot de passe est incorrect");
    }
} while (login != loginATrouver || motDePasse != motDePasseATrouver);
Console.WriteLine("Bravo vous avez trouvé!!");
Amélioration de l'algorithme du mot de passe - 3

Tout d'abord nous créons une variables "tentatives" avant la boucle, nous l'initialisons à 0 (à ce niveau là, aucune tentative n'a encore été faite). Ensuite, pour chaque tentative, nous incrémentons le nombre de tentative et vérifions à combien de tentatives nous en sommes avant de décider si nous bouclons à nouveau ou non. L'incrémentation et la vérifications peuvent se faire en même temps en faisant un pré-incrémentation ("++tentatives ") dans l'expression booléenne de la boucle.

Et pour finir, à la sortie de la boucle, nous vérifions le nombre de tentatives pour voir si l'on a trouvé ou non.

string loginATrouver = "zozor", motDePasseATrouver = "P4ssw0rD";
string login, motDePasse;
int tentatives = 0;
do
{
    Console.Write("Tapez votre login: ");
    login = Console.ReadLine();
    Console.Write("Tapez votre mot de passe: ");
    motDePasse = Console.ReadLine();
    if (login != loginATrouver)
    {
        Console.WriteLine("Le login est incorrect");
    }
    else if (motDePasseATrouver != motDePasse)
    {
        Console.WriteLine("Le mot de passe est incorrect");
    }
} while ( (login != loginATrouver || motDePasse != motDePasseATrouver) && ++tentatives <= 2);

if (tentatives < 3)
    Console.WriteLine("Bravo vous avez trouvé!!");
else
    Console.WriteLine("Vous avez échoué");

Si vous n'avez pas correctement intégré ce chapitre, n'hésitez surtout pas à revenir dessus!! Il est très important, non pas pour comprendre spécifiquement le langage C# , mais pour réaliser n'importe quel programme dans n'importe quel langage.

Cette partie n'est pas encore terminée, elle sera complétée au fur et à mesure

Exemple de certificat de réussite
Exemple de certificat de réussite