Buggle Dance Revolution (BDR)

Aujourd'hui est un grand jour : nous allons apprendre à nos buggles à jouer à Dance Revolution, ce jeu très prisé de certains étudiants où le joueur doit bouger sur un tapis prévu à cet effet en fonction des consignes présentées à l'écran en rythme avec la musique. Mais avant cela, nous avons quelques détails à étudier.

[!java|scala]

Conditionnelles sans accolades

Il y a un détail que nous avons omis à propos de la syntaxe des conditionnelles : si une branche ne contient qu'une seule instruction, les accolades sont optionnelles. Ainsi, les deux extraits suivants sont équivalents:

if (condition) {
    quoiFaireSiLaConditionEstVraie();
} else {
    quoiFaireSinon();
}
if (condition)
    quoiFaireSiLaConditionEstVraie();
else
    quoiFaireSinon();

Vous pouvez faire de même avec les boucles dont le corps se réduit à une seule instruction. Mais attention, ceci peut être dangereux si on enchaîne les if comme dans l'exemple suivant.

if (estSurBiscuit())    
     if (x == 5)
          gauche();
else
     droite();
avance();

En fait, ça ne tourne pas à droite quand il n'y a pas un baggle par terre ET que x vaut 5, mais quand la buggle a trouvé un baggle, et que x vaut une autre valeur. Autrement dit, la buggle lit le code précédent comme suit (notez que le else est décalé vers la droite par rapport à précédemment) :

if (estSurBiscuit())    
        if (x == 5)
            gauche();
        else
            droite();
avance();

La première leçon, c'est que l'indentation est très importante pour que les humains puissent comprendre le code, mais elle ne change pas la signification du code pour la machine. On aurait tout aussi bien pu écrire le code suivant et obtenir le même résultat. Mais attention, si on veut qu'un humain puisse relire le code, l'indentation est quasi indispensable. C'est par exemple le cas si votre code doit être relu par un professeur (pour qu'il le note ou pour lui poser une question), ou si vous comptez réutiliser votre code plus tard, ou même si vous devez debugger votre propre code après l'avoir écrit.

if (estSurBiscuit()) if (x == 5) gauche(); else droite(); avance();

La seconde leçon, c'est qu'une branche else se raccroche toujours au if le plus proche. C'est parfois un peu contre-intuitif, et il est préférable d'ajouter plus d'accolades que nécessaire pour lever toute ambiguïté.

[/!]

Enchaînements de conditionnelles

Il arrive que l'on veuille demander à la buggle quelque chose similaire à :

s'il pleut, prend un parapluie; 
si non, s'il fait chaud, prend une bouteille d'eau; 
si non, si nous sommes le 14 juillet, prend un drapeau français

Le piège étant que nous voudrions qu'au plus l'une de ces actions soient réalisées. C'est à dire, que s'il pleut un 14 juillet très chaud, on ne veut pas que la buggle sorte avec un parapluie, de l'eau et un drapeau, mais juste avec un parapluie. Le code suivant est donc faux.

[!java|scala]if (ilPleut())
    prendreParapluie();
if (ilFaitChaud())
    prendreDeLEau();
if (sommes14Juillet())
    prendreDrapeau();[/!][!python]if ilPleut():
    prendreParapluie()
if ilFaitChaud():
    prendreDeLEau()
if sommes14Juillet():
    prendreDrapeau()[/!]

En effet, toutes les conditions sont évaluées les unes après les autres, et on risque donc d'aller au défilé un jour de pluie. À la place, il faut donc écrire quelque chose comme ce qui suit pour s'assurer que si l'on trouve une condition vraie, on n'évalue pas les suivants.

[!java|scala]if (ilPleut()) {
    prendreParapluie();
} else {
    if (ilFaitChaud()) {
        prendreDeLEau();
    } else {
        if (sommes14Juillet()) {
            prendreDrapeau();
        }
    }
}[/!][!python]if ilPleut():
    prendreParapluie()
else:
    if ilFaitChaud():
        prendreDeLEau()
    else:
        if sommes14Juillet():
            prendreDrapeau()[/!]

Une telle cascade de conditionnelles est un peu difficile à lire, et il est préférable [!java|scala] d'omettre les accolades associées aux else comme suit. Il y a même certains langages qui introduisent un mot-clé spécial pour ces else if (mais pas [!thelang]).[/!] [!python] d'introduire les sous-blocs avec le mot-clé elif (abréviation de «else if») pour expliciter ces branches «sinon si».[/!]

[!java|scala]if (ilPleut()) { 
    prendreParapluie();
} else if (ilFaitChaud()) {
    prendreDeLEau();
} else if (sommes14Juillet()) {
    prendreDrapeau();
}[/!][!python]if ilPleut():
    prendreDrapeau()
elif ilFaitChaud():
    prendreDeLEau()
elif sommes14Juillet():
    prendreDrapeau()[/!]

Les graffitis dans le monde des buggles

Les buggles peuvent écrire des choses par terre dans leur monde. Pour ce faire, elles utilisent les quatre méthodes suivantes:

Objectif de cet exercice

L'objectif est donc d'organiser une partie de BDR entre les buggles en leur apprenant à bouger en fonction des indications écrites par terre. Ces indications sont des messages au sol, avec le code suivant:
Indication Quoi faire Mnémotechnique
[!java]'R'[/!][!scala|python]"R"[/!]Tourner à droite et avancer d'une caseRight
[!java]'L'[/!][!scala|python]"L"[/!]Tourner à gauche et avancer d'une caseLeft
[!java]'I'[/!][!scala|python]"I"[/!]Se retourner (demi-tour) et avancer d'une caseInverse
[!java]'A'[/!][!scala|python]"A"[/!]Avancer d'une casePremière lettre de l'alphabet
[!java]'B'[/!][!scala|python]"B"[/!]Avancer de deux casesDeuxième lettre de l'alphabet
[!java]'C'[/!][!scala|python]"C"[/!]Avancer de trois casesTroisième lettre de l'alphabet
[!java]'Z'[/!][!scala|python]"Z"[/!]Reculer d'une caseA une lettre de la fin de l'alphabet
[!java]'Y'[/!][!scala|python]"Y"[/!]Reculer de deux casesA deux lettres de la fin de l'alphabet
[!java]'X'[/!][!scala|python]"X"[/!]Reculer de trois casesA trois lettres de la fin de l'alphabet
(n'importe quoi d'autre)Arrêter de dancer.

Indications

Cet exercice peut sembler un peu compliqué, mais il s'agit principalement de traduire le contenu du tableau ci-dessus dans un enchaînement de conditionnelles.

Vous devez continuer à danser tant qu'il reste des pas de danse à faire. c-à-d tant qu'on a pas trouvé une case n'étant pas décrite dans le tableau. Le plus simple pour cela est d'utiliser une variable booléenne (fini) en condition d'arrêt d'une boucle while. Cette variable est initialisée à la valeur faux ([!java|scala]false[/!][!python]False[/!]). Si on trouve une case ne répondant à aucune ligne du tableau, on change la valeur de cette variable à vrai ([!java|scala]true[/!][!python]True[/!]). Cela arrête la boucle, et le programme.

[!java]

Une autre subtilité est que déterminer si des chaînes de caractères est un peu pénible en Java. Nous utiliserons donc la méthode char getIndication() à la place de String litMessage(). Cette méthode, qui n'est connue que des buggles des exercice BDR, renvoie le premier caractère du message au sol (ou ' ' --une espace-- s'il n'y a rien d'écrit au sol). Cela nous permet de travailler avec des caractères (char), qui sont moins pénibles que les chaînes.

[/!]

Trucs et astuces

Si vous ne parvenez plus à comprendre pourquoi votre buggle n'exécute pas les pas de danse demandés, essayez d'ajouter baisseBrosse() dans votre méthode. Cela demandera à la buggle de poser une brosse par terre, laissant une trace au sol quand elle avance. Cela devrait vous aider à suivre sa trajectoire, mais pensez à retirer cette appel lorsque vous voulez tester si votre solution marche : on vous demande de faire danser les buggles, pas de dégrader le dance floor.

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