## Buggle Dance Revolution 2 (BDR2)

[!java|scala|c]

Le BDR, c'est cool, mais c'est un peu le chaos. Tout d'abord, les buggles gigotent en tout sens, et en plus, le code que vous avez écrit pour les faire bouger est très difficile à lire. Voici un nouveau monde de BDR, où les buggles vont faire une gentille petite ronde plus reposante. Nous profiterons de cette accalmie pour nettoyer un peu le code grâce aux nouveaux éléments que nous allons maintenant étudier.

### [!java|c]Conditionnelle `switch`[/!][!scala]Les filtrages[/!]

Le plus difficile à lire du code précédent est certainement la cascade de conditionnelles. Quelque part dans votre programme, vous avez sans doute écrit quelque chose comme:

    if ([!java|c]getIndication() == 'R'[/!][!scala]litMessage() == "R"[/!]) {
      droite();
      avance();
    } else if ([!java|c]getIndication() == 'L'[/!][!scala]litMessage() == "L"[/!]) {
      gauche();
      avance();
    } else if ([!java|c]getIndication() == 'I'[/!][!scala]litMessage() == "I"[/!]) {
      retourne();
      avance();
    /* d'autre if */
    } else {
      fini = true;
    }

À la première lecture du code, il n'est pas évident qu'il ne s'agit que d'un choix avec 4 branches en fonction du résultat de [!java]getIndication()[/!][!scala]litMessage()[/!]. Pour améliorer ceci, nous allons utiliser [!java]un `switch`, dont la syntaxe est la suivante en Java.[/!] [!scala] un filtrage (pattern matching en anglais), qui est une construction très agréable généralisant le `if`. Il s'agit sans aucun doute de l'un des avantages majeurs du langage Scala par rapport à d'autres tels que le Java ou le Python. Cette construction n'est cependant pas révolutionnaire puisqu'elle existe depuis assez longtemps dans des langages comme OCaml ou Haskell, mais il n'empêche. Elle est carrément cool![/!]

[/!] [!java|c]

    switch (expression) {
      case premierValeur:
        queFaireSiExpressionVautPremiereValeur();
        break;
      case deuxiemeValeur:
        queFaireSiExpressionVautDeuxiemeValeur();
        break;
      case troisiemeValeur:
        queFaireSiExpressionVautTroisiemeValeur();
        break;
        /* autant de cas sur le même modèle qu'on le souhaite */
      default:
        queFaireSiExpressionVautAucuneDesValeursProposees();
    }

Remarquez que chaque branche du `switch` doit être terminée par un `break`. Si on l'oublie, la machine continue d'exécuter le cas suivant dans la liste quand elle a fini le code du cas où elle a sauté dans le switch. Il y a même quelques très rares cas où ce comportement est pratique.

On peut réécrire le code BDR précédent bien plus clairement grâce à la construction `switch` de la façon suivante.

    switch (getIndication()) {
      case 'R':
        droite();
        [!c]avancePas()[/!][!java]avance()[/!];
        break;
      case 'L':
        gauche();
        [!c]avancePas()[/!][!java]avance()[/!];
        break;
      case 'I':
        retourne();
        [!c]avancePas()[/!][!java]avance()[/!];
        break;
      default:
        return;
    }

[/!] [!scala]

    expression match {
      case valeur possible  => instructions
      case autre valeur     => d'autres instructions
      case troisième valeur => encore d'autres instructions
      case _                 => instructions par défaut
    }

L'expression fournie avant le mot-clé `match` est évaluée, et ensuite, les branches sont évaluées les unes après les autres jusqu'à en trouver une où la valeur entre le `case` et le `=>` correspond à la valeur de l'expression. Le symbole `_` agit comme un joker qui correspond à tout. Cela veut dire que la dernière ligne telle qu'elle est écrite correspond toujours à la valeur fournie, quelle qu'elle soit. Voici un petit exemple où une variable `nom` est mis en correspondance.

    nom match {
      case "Martin" => println("Salut Martin, comment vas-tu?")
      case "Gerald" => println("He Gerald! Ça va?")
      case _            => println("Bonjour, étranger.")
    }

Il est aussi possible d'avoir plusieurs instructions par branches, et même d'avoir plusieurs valeurs sur une branche donnée, séparées par le caractère `|`.

    nom match {
      case "Martin" | "Gerald" => println("Bonjour "+nom+", entre."); ouvreLaPorte()
      case _                            => println("Bonjour étranger. Passe ton chemin sans entrer."); fermeLaPorte()
    }

Il est même possible d'ajouter des gardes à vos branches. Il s'agit de conditions supplémentaires qui doivent être respectées pour que la branche soit appliquée. C'est par exemple pratique pour faire du filtrage sur un ensemble de valeurs.

    age match {
      case i if i<10 => println("Salut gamin!")
      case i if i<20 => println("Salut mec")
      case i if i<30 => println("Bonjour jeune homme")
      case _           => println("Bonjour monsieur")
    }

Remarquez qu'il n'est pas nécessaire de vérifier à la seconde ligne que la valeur est supérieure à 10 puisque les lignes sont considérées dans l'ordre. Si la seconde ligne est considérée, c'est que la première ne correspondait pas.

Enfin, il est même possible de filtrer sur plusieurs variables à la fois!

    (x,y) match {
     case (0,0) => println("C'est le point origine")
     case (_,0) => println("C'est un point de l'ordonnée")
     case (0,_) => println("C'est un point de l'abscisse")
     case (_,_) => println("C'est un point quelconque")
    }

Je vous avais bien dit que le filtrage scala était une construction surpuissante ! Je l'adore !

[/!]

### Objectif de cet exercice

[!java|scala|c]Appliquez les améliorations que nous venons de voir pour adapter le code de votre buggle au nouveau pas de danse explicité ci-dessous.[/!] [!python]Nous allons maintenant apprendre un nouveau pas de danse à nos buggles. Il est un peu plus complexe, mais sinon, c'est toujours la même histoire.[/!] Remarquez qu'il est maintenant possible d'avancer jusqu'à 6 cases à la fois.

Indication | Quoi faire
[!java|c]'R'[/!][!scala|python]"R"[/!] | Tourner à droite et avancer d'une case
[!java|c]'L'[/!][!scala|python]"L"[/!] | Tourner à gauche et avancer d'une case
[!java|c]'I'[/!][!scala|python]"I"[/!] | Se retourner (faire demi-tour) et avancer d'une case
[!java|c]'A'[/!][!scala|python]"A"[/!] | Avancer d'une case
[!java|c]'B'[/!][!scala|python]"B"[/!] | Avancer de deux cases
[!java|c]'C'[/!][!scala|python]"C"[/!] | Avancer de trois cases
[!java|c]'D'[/!][!scala|python]"D"[/!] | Avancer de quatre cases
[!java|c]'E'[/!][!scala|python]"E"[/!] | Avancer de cinq cases
[!java|c]'F'[/!][!scala|python]"F"[/!] | Avancer de six cases
[!java|c]'Z'[/!][!scala|python]"Z"[/!] | Reculer d'une case
[!java|c]'Y'[/!][!scala|python]"Y"[/!] | Reculer de deux cases
[!java|c]'X'[/!][!scala|python]"X"[/!] | Reculer de trois cases
[!java|c]'W'[/!][!scala|python]"W"[/!] | Reculer de quatre cases
[!java|c]'V'[/!][!scala|python]"V"[/!] | Reculer de cinq cases
[!java|c]'U'[/!][!scala|python]"U"[/!] | Reculer de six cases
(n'importe quoi d'autre) | Arrêter de danser.

Quand votre programme fonctionne de nouveau, passez à l'exercice suivant.