-
Cours :
- cours 1 transparents : pdf
- cours 2 transparents : pdf
- cours 3 transparents : pdf
- cours 4 transparents : pdf
- cours 5 transparents : pdf
- cours 6 transparents : pdf
- cours 7 transparents : pdf
- cours 8 transparents : pdf
- cours 9 transparents : pdf
- cours 10 transparents : pdf
- cours 11 transparents : pdf
- cours 12 transparents : pdf
- Documents :
- TD :
- TP :
- TP 8 (pdf)
- TP 9 (pdf)
- TP 10 (pdf), Corrigé TP 10 (pdf)
- Projet astéroïdes (pdf)
TD 8 : Bataille navale
Description du jeu de bataille navale
À la bataille navale (battleship game), le plateau de jeu est représenté par une grille rectangulaire de cases sur lesquelles on peut poser des bateaux. Les bateaux sont larges d’une case et longs d’un nombre variable de cases. Ils peuvent être posés verticalement ou horizontalement sur le plateau.
Le plateau est masqué au joueur qui attaque et celui-ci doit couler tous les bateaux du joueur défenseur (defender). Pour cela, il propose une position du plateau qui désigne la case sur laquelle il tire.
Plusieurs cas sont alors possibles :
- si cette case n’est pas occupée par un bateau, le défenseur annonce dans l’eau (missed) ;
- dans le cas contraire, le défenseur annonce touché (hit) si toutes les cases occupées par le bateau touché n’ont pas déjà été visées par l’attaquant,
- le défenseur annonce coulé (sunk) si toutes les autres cases du bateau ont déjà été touchées.
- lorsqu’une case avait déjà été visée précédemment, la réponse est toujours dans l’eau.
On s’intéresse à certains aspects de la programmation en Java d’un ensemble de classes permettant la programmation de ce jeu.
La classe Ship
Spécification de la classe Ship
La classe Ship
permet de représenter les bateaux. Une instance de Ship
est construite avec une longueur et un nom. La longueur d’un bateau détermine son nombre de points de vie initial (life points). Lorsqu’il est touché (méthode takeAHit()
), ce nombre est décrémenté d’un. Un bateau est coulé quand son nombre de points de vie arrive à 0 (méthode hasBeenSunk()
).
Voici le diagramme de cette classe :
Questions
Question 1 : Donner le code définissant les attributs de
Ship
ainsi que le constructeur de la classe.
Question 2 : Donnez la méthode de tests qui permet de vérifier la spécification du comportement de la méthode
takeAHit()
.
La classe Cell
Spécification de la classe Cell
La classe Cell
permet de représenter les cases du plateau de jeu. Son diagramme de classe est donné ci-dessous. Une case est initialement vide. Mais elle peut être occupée par un seul bateau (méthode getShip()
). Il faut donc pouvoir poser un bateau sur une case (méthode setShip()
). L’attaquant peut tirer sur une case (méthode takeAShot()
). Si la case est occupée, lors du premier de ces tirs, cela a pour conséquence que le bateau correspondant est touché. Seul le premier tir sur une case compte, un bateau ne peut pas être touché deux fois par un tir sur la même case. Il est donc nécessaire de pouvoir savoir si une case a déjà été visée ou non par un tir de l’attaquant (peu importe qu’elle comporte initialement un bateau ou non) grace à la méthode hasBeenShot()
.
On appelle ShotResult
le type permettant de représenter les 3 réponses possibles après un tir d’un attaquant : MISSED
, HIT
et SUNK
.
Questions
Question 3 : Comment peut-on définir le type
ShotResult
?
Question 4 : Comment peut-on gérer la présence ou l’absence d’un bateau sur une case ?
Question 5 : Donnez la ou les méthodes de tests qui permettent de vérifier cette spécification du comportement de la méthode
takeAShot()
.
Question 6 : Donnez le code de la méthode
takeAShot()
.
La classe Coordinates
Spécification de la classe Coordinates
Pour représenter les coordonnées des cases du plateau de jeu, on définit la classe Coordinates
. La méthode toString
renvoie un chaîne de caractère au format suivant : (X, Y)
avec X
la coordonnée en \(x\) et Y
la coordonnée en \(y\). Deux positions sont considérées égales si elles ont les mêmes coordonnées en \(x\) et en \(y\).
Questions
Question 7 : Comment peut-on rendre les instances de
Coordinates
immuables ?
Question 8 : Donnez le code de la méthode
equals
deCoordinates
.
La classe Grid
Spécification de la classe Grid
La classe représentant le plateau de jeu (la grille) s’appelle Grid
. On décide de représenter son état par un tableau à deux dimensions de cases qui sont des objets de type Cell
.
La méthode shootAt
de la classe Grid
est utilisée lorsque le joueur attaquant vise une case. Son résultat est la réponse lorsque l’attaquant vise la case située à la position p
sur le plateau de jeu. La position p
est passée en paramètre de la méthode.
Questions
Question 9 : Donnez le code définissant les attributs de
Grid
ainsi que le constructeur de la classe sachant qu’initialement toutes les cases sont vides (pas de bateau) et que les dimensions du plateau de jeu sont fixées à la construction de l’objet.
Question 10 : Dessinez le diagramme de classe de
Grid
.
Question 11 : Donnez la signature, la javadoc, les méthodes de test et le code de la méthode
shootAt
deGrid
.
Rappels sur les tests
Méthodologie de test
Une classe de test par classe à tester. Une méthode de test par méthode ou cas à tester.
Le code d’une classe de test testant une classe NameTestedClass
a le format suivant :
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class NameTestedClassTest {
@Test
void testTestMethod(){
// code containing assertions
} }
Assertions (liste non-exhaustive)
Pour tester, on utilise des assertions qui doivent être vraies. Vous trouverez ci-dessous une listes des assertions les plus utiles.
assertThat(object).isNotNull()
: vérifie que la référence n’est pasnull
assertThat(actual).isSameAs(expected)
: vérifie que les deux objets sont les mêmes (même référence : utilisation de==
).assertThat(condition).isTrue()
: vérifie quecondition
est vraie.assertThat(condition).isFalse()
: vérifie quecondition
est faux.assertThat(actual).isEqualTo(expected)
: vérifie queexpected
est égal àactual
(en appelantequals
suractual
).assertThat(actual).isNotEqualTo(expected)
: vérifie queexpected
n’est égal pas àactual
(en appelantequals
suractual
).assertThat(iterable).contains(element)
: vérifie queiterable
(qui peut être uneList
, un tableau, … ) contientelement
.assertThat(iterable).containsOnly(element)
: vérifie queiterable
(qui peut être uneList
, un tableau, … ) contient seulementelement
.assertThat(actual).isCloseTo(expected, within(delta))
: vérifie que \(|expected - actual|\leq delta\) (comparaison de double).