TP 3.2 2324v1
Avant de commencer ce TP, le TP 3.1 doit être entièrement terminé, avec tous nos tests
et vos tests réussis.
Si ce n'est pas le cas, demandez de l'aide à l'intervenant dès le début du TP.
I. Suite de la classe Game
- Ajouter une procédure privée printWelcome sans aucun paramètre (qui sera appelée au début du jeu, dans la partie III.) pour afficher le message suivant (notez que les 2 dernières lignes changeraient si le lieu initial n'était pas 'main entrance') :
Welcome to the World of Zuul! World of Zuul is a new, incredibly boring adventure game. Type 'help' if you need help. You are outside the main entrance of the university Exits: east south west
|
Remarquez qu'on affiche juste les directions possibles, pas les lieux.
- Ajouter 2 méthodes privées printHelp et quit (qui seront exécutées lorsqu'on tapera respectivement
les commandes "help"
et "quit") :
a) La première est une procédure (sans aucun paramètre) qui affiche :
You are lost. You are alone. You wander around at the university.
Your command words are: go quit help
|
Lorsque vous n'avez plus d'erreur de compilation, clic-droit sur la classe GameTest et exécuter testprint_6().
Si
vous voyez apparaître tout en bas la mention 'testprint_6
succeeded', vous pouvez passer à la suite. Sinon, vous devez voir
apparaître une fenêtre 'BlueJ: Test Results'. Cliquer sur la ligne
'v1.GameTest.testprint_6' pour voir le message d'erreur sous la barre rouge.
b) La seconde est une fonction booléenne qui prend une Command en paramètre. S'il y a un second mot, elle retourne faux après avoir affiché "Quit what ?".
Sinon, elle se contente de retourner vrai.
(indice au VI.1)
Lorsque vous n'avez plus d'erreur de compilation, clic-droit sur la classe GameTest et exécuter testquit_7().
Si
vous voyez apparaître tout en bas la mention 'testquit_7
succeeded', vous pouvez passer à la suite. Sinon, cliquez sur la ligne
'v1.GameTest.testquit_7' pour voir le message d'erreur sous la barre rouge.
- Ajouter maintenant une fonction booléenne privée processCommand qui prend une Command en paramètre. Son rôle est d'appeler
la bonne méthode en fonction de la commande passée en paramètre.
a) Si la commande est inconnue , elle retournera faux après avoir affiché le message "I don't know what you mean...".
b) Sinon, après avoir appelé la méthode correspondant à la commande, elle retournera :
- soit le résultat (booléen) de quit() (dans le cas de la commande "quit"),
- soit systématiquement faux (pour les autres commandes).
c) Si aucun mot de commande n'a été reconnu, afficher
"Erreur du programmeur : commande non reconnue !",
car cela aurait dû être détecté par
isUnknown().
(indice au VI.2)
Lorsque vous n'avez plus d'erreur de compilation, clic-droit sur la classe GameTest et exécuter testprocessCommand_8().
Si
vous voyez apparaître tout en bas la mention 'testprocessCommand_8
succeeded', vous pouvez passer à la suite. Sinon, cliquez sur la ligne
'v1.GameTest.testprocessCommand_8' pour voir le message d'erreur sous la barre rouge.
- Vérifier interactivement le bon fonctionnement de cette deuxième version de la classe Game. Vous pouvez rendre publiques les méthodes que vous voulez tester, puis les remettre privées puisqu'elles
n'auront pas vocation à être appelées en dehors de cette classe.
II. Créer les deux dernières classes
- Créer une classe CommandWords
qui contiendra les mots de commande acceptés par le jeu. Pour cela :
- Déclarez comme unique attribut un tableau de chaînes de caractères,
constant (==> non modifiable : quel mot java permet ça ?)
que nous appellerons aValidCommands
et que nous initialiserons avec les 3 seules commandes reconnues par le jeu
pour l'instant.
(voir les rappels de syntaxe sur les tableaux ci-dessous)
- Comme cette classe ne contient qu'un attribut constant, pas besoin de constructeur.
(pour information, Java crée automatiquement un constructeur par défaut avec un corps vide)
- Compilez.
Quand il n'y a plus d'erreurs, clic-droit sur la classe
et Créer classe Test.
Écrasez tout le code par celui contenu dans le fichier
CommandWordsTest.java tout en bas de cet énoncé.
Compilez. Exécutez la méthode testconstructeur_3().
Tout est vert ?
- Écrivez maintenant une fonction booléenne isCommand qui pourra dire si oui ou non
le mot qu'on lui passe en paramètre fait partie des commandes reconnues.
Pour cela, elle parcourera simplement le tableau des commandes reconnues
et retournera sa réponse dès qu'elle l'aura trouvée.
- Lorsque vous n'avez plus d'erreur de compilation, clic-droit
sur la classe CommandWordsTest et exécuter
testisCommand_4().
Ce qu'il faut retenir sur les tableaux
- Un tableau permet de regrouper/manipuler plusieurs données de même type. Par exemple, pour un tableau de String, on trouverait une String dans
chaque case du tableau.
- Lorsqu'on ajoute [] après un type T, cela crée un nouveau type 'tableau d'éléments de type T ' qui fait partie des types objet (ou reference types).
Par exemple, boolean[] désigne un type 'tableau de booléens', mais T peut très bien être une classe ou n'importe
quel autre type.
- On déclare les tableaux comme toute autre variable (locale, attribut ou paramètre) en utilisant le type int[] si c'est un tableau d'entiers. Par exemple, pour une variable locale, on écrirait : int[] vTab;
Attention !
Comme pour les objets, l'instruction précédente ne crée aucun tableau ;
elle déclare juste une variable référence qui pourra contenir l'adresse
d'un tableau d'entiers.
- On crée les tableaux presque comme on crée les objets : vTab = new int[12]; si on veut un tableau de 12 entiers. La variable vTab contient alors la référence vers l'objet tableau qui ici comporte 12 cases, chacune pouvant contenir un entier.
- On peut connaître la taille de tout tableau en utilisant l'attribut public length qui est automatiquement créé lors de la création du tableau (attention, ce n'est pas une fonction,
rien à voir avec length() de la classe String).
- Chaque case du tableau est numérotée de 0 à la taille-1. Ces numéros s'appellent des indices.
- On accède à une case du tableau par son indice, et vTab[indice] peut servir à la fois pour lire la valeur dans la case et pour y écrire une nouvelle valeur. Si indice est
hors des limites 0 à taille-1, une exception est générée et, en général, le programme s'arrête.
- Il existe une manière courte de déclarer+créer+initialiser un tableau de type T quand on connaît toutes ses valeurs :
T
[] vTab = { valeur0, ..., valeurN-1 };
- On ne peut pas afficher les valeurs d'un tableau par un simple S.o.p(vTab); qui se contenterait d'afficher l'adresse (= la référence) de ce tableau.
Ce qu'il faut retenir sur la boucle for
C'est une boucle souvent utilisée avec les tableaux. Même si elle est rigoureusement équivalente à une boucle while
(comme on pourra le constater ci-dessous), il est très pratique
d'avoir toutes les informations rassemblées en une ligne au lieu d'être
potentiellement dispersées dans une méthode.
On l'utilise à chaque fois que l'on souhaite exprimer une répétition un
nombre connu de fois.
L'ensemble des instructions :
initialisation
;
while ( condition_de_continuation
) {
instructions_à_répéter
;
incrémentation
;
} // while
peut/doit avantageusement être remplacé par :
for (
initialisation ;
condition_de_continuation ;
incrémentation ) {
instructions_à_répéter
;
} // for
Ce qu'on appelle initialisation comprend en général la déclaration, par exemple : int i=0;
Ce qu'on appelle incrémentation est en général de la forme i = i+1, mais rien n'empêche
d'écrire i = i-2 et d'adapter l'initialisation et la condition en
conséquence !
Attention ! La condition_de_continuation (comme son nom l'indique) n'est pas une condition d'arrêt !
Il est important de noter que l'incrémentation a lieu en fin de boucle, après les instructions_à_répéter.
A noter également : c'est le seul cas en java où un point-virgule (à l'intérieur des parenthèses) ne marque pas la fin de l'instruction for !
Si ça ne suffit pas, vous pouvez aussi lire ce
mini-cours
sur la boucle for
- Créer une classe Parser
qui lira la commande tapée au clavier, vérifiera qu'elle est valide, et qui construira l'objet Command correspondant.
Comme il y a beaucoup de nouvelles notions importantes dans cette
classe, copiez/collez le code de la classe jointe en bas de ce sujet, et nous reviendrons sur ces notions au TP suivant.
En attendant lire la description ci-dessous :
- déclaration d'un objet de la classe CommandWords qui gèrera la validité des commandes tapées (L23) et d'un objet Scanner qui ira lire les commandes tapées au clavier (L24)
- constructeur par défaut qui crée les 2 objets déclarés en attribut (L29-34) (à quoi les attributs sont-ils initialisés ?)
- une fonction qui retourne un objet Command en fonction de la commande tapée au clavier (L39-47) ; son principe :
1) s'il y a un mot dans la ligne tapée, le mémoriser dans un 1er mot, puis s'il y a encore un mot, le mémoriser dans le 2nd mot. (L50-57)
2) Demander à l'objet CommandWords si le premier mot correspond à une commande valide ou pas. (L62)
3) Si oui, retourner un nouvel objet Command composé des deux mots (le second pouvant éventuellement être null) (L63) ; sinon, retourner un nouvel objet Command contenant 2 fois null (L66).
Plus de détails sur le Scanner
dans l'exercice 7.2.1 (partie V.).
III. Pour obtenir un jeu qui fonctionne
- Tous les éléments nécessaires sont désormais réunis, il ne manque plus dans la classe Game qu'un attribut aParser (objet qu'il
ne faudra pas oublier de créer dans le constructeur) et une procédure play()sans paramètre qui devra lire répétitivement des commandes au clavier et les exécuter jusqu'à ce qu'on
tape
"quit".
Pour cela, elle devra :
- Afficher le message de bienvenue.
- Initialiser une variable booléenne vFinished à faux pour signifier qu'on ne veut pas quitter le jeu.
- TANT QUE cette variable est fausse, faire 2 choses :
a) Récupérer dans une variable de type Command la commande tapée au clavier.
b) Mettre dans vFinished le résultat de l'exécution de la commande.
+ Pour exprimer un 'TANT QUE' en java, il suffit de le traduire en anglais : while. La syntaxe est la même que
celle d'un if,
c'est-à-dire que la condition doit être entre parenthèses et une seule
instruction peut la suivre (sauf si on met des accolades, bien entendu).
- Afficher un message de fin : "Thank you for playing. Good bye.".
- Vérifier maintenant que le jeu est parfaitement fonctionnel en lançant la méthode play() sur un objet Game ;
ensuite, appeler cette méthode (redevenue privée) dans le constructeur.
Ne pas hésiter à tester tous les cas.
Ce qu'il faut retenir sur la boucle while
La syntaxe est identique à celle d'un if (faire bien attention de ne pas les confondre !) :
avant...
while ( condition
) {
instructions
} // while
après...
La boucle ci-dessus répète les instructions tant que la condition reste vraie.
Quatre remarques :
- Si la condition est fausse avant d'arriver sur le
while, les instructions ne seront jamais exécutées
- Dans tous les cas, si on se retrouve après le while, c'est que la condition est fausse.
- La boucle while s'utilise à chaque fois qu'on ne peut pas prévoir en rentrant dans la boucle combien de fois elle va tourner (puisqu'on ne sait pas quand la condition deviendra fausse).
- Dans la condition, ne pas utiliser
== ou
!=
avec des nombres, mais
plutôt < <= >
ou >=.
IV. Compétences à vérifier
Après les TP 3.1 & 3.2, √érifiez que vous avez acquis les compétences ci-dessous, ainsi que celles du TP1 et celles du TP2.
- expliquer à quoi sert le mot null en java ;
- expliquer le rôle du constructeur d'une classe, et la différence entre le constructeur par défaut et le constructeur naturel ;
- expliquer dans quel cas et à quoi sert l'instruction return; (sans valeur !) ;
- écrire l'instruction qui permet d'afficher un message dans un terminal, et expliquer la conséquence de mettre ou pas ln à la fin de cette instruction ;
- expliquer comment et dans quel cas on peut se passer de if pour écrire une fonction booléenne ;
- expliquer la différence entre if (x<0) y=1; else y=2; et if (x<0) y=1; if (x>=0) y=2;
- expliquer la différence entre x=y; et x==y, puis entre x==y et
x.equals(y);
V. Avancement du projet
- Lire les premiers liens de la
Liste
officielle des exercices
jusqu'au 7.0 non compris.
- Faire l'exercice 7.1 (lecture).
- Faire l'exercice 7.2.1 (compréhension) et lire le A SAVOIR EXPLIQUER qui suit.
- Faire les exercices 7.3, 7.3.1, et 7.3.2.
(éventuellement les repousser pour mieux profiter d'un intervenant disponible)
- Lire l'exercice 7.3.3 et éventuellement l'appliquer si vous êtes concerné.
VI. Indices pour ce TP
1) Indices pour écrire la méthode quit :
- La situation normale est l'absence de second mot. Dans ce cas, se contenter de retourner vrai (pour quitter le jeu).
- Dans le cas contraire, afficher un message et retourner faux (pour ne pas quitter le jeu).
2) Indices pour écrire la méthode processCommand :
- Comprendre la nature de ce qui lui est passé en paramètre.
- Traiter le cas où la
commande est inconnue : une fonction écrite dans un exercice précédent
nous permet de le savoir, il faut afficher un message et terminer la
fonction (en indiquant qu'on ne veut pas quitter le jeu => retourner faux).
- Mémoriser le mot de commande à tester.
- Tester chaque mot de commande pour exécuter la bonne commande en appelant la méthode correspondante, et retourner faux (sauf la commande quit qui doit retourner le résultat booléen de la fonction quit).
- À la fin de ces tests,
si vous n'avez détecté aucun mot de commande valide, c'est que vous avez fait une erreur :
soit isUnknown()
ne fonctionne pas bien, soit ces tests ne sont pas bons.
Choisissez bien l'enchaînement des if ou des if/else, et rappelez-vous que les chaînes de caractères sont des objets !
Si vous n'arrivez toujours pas à terminer ces exercices
(notamment en travail personnel), demandez de l'aide sans attendre.
La séance Résa 3.2 est obligatoire pour tous ceux qui n'ont pas terminé
les TP 3.1 & 3.2.