-
Cours :
- Notions programmation orientée objet et Java (pdf)
- Tests (pdf)
- Principes SOLID (pdf)
- Patrons de conception (pdf)
-
Planches de TD :
- TD 1 (pdf), Corrigé TD 1 (pdf)
- TD 2 (pdf), Corrigé TD 2 (pdf)
- TP 1 (pdf), Corrigé TP 1 (pdf)
Corrigé TP 2 : Bataille navale
Tâche 1 : Créez la classe
Ship
dans le répertoiresrc/main/java
de votre projet qui répond aux spécifications ci-dessus. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class Ship {
private int lifePoints;
private final String name;
/**
* Construct a ship with the specified length and name.
*
* @param length the initial number of life points of the ship
* @param name the name of the ship
*/
public Ship(int length, String name) {
this.lifePoints = length;
this.name = name;
}
/**
* Return {@code true} if this ship has zero life points.
* @return {@code true} if this ship has zero life points
*/
public boolean hasBeenSunk(){
return getLifePoints() == 0;
}
/**
* Returns the number of life points of this ship.
* @return the number of life points of this ship
*/
public int getLifePoints() {
return lifePoints;
}
/**
* Decrements by one the number of life points of this ship (minimum 0).
*/
public void takeAHit(){
if(lifePoints>0)
--;
lifePoints}
/**
* Returns a string representation of this ship with its name and
* its number of life points.
* @return a string representation of this ship
*/
@Override
public String toString() {
return name + " (" + lifePoints + " LP)";
}
}
Tâche 2 : Créez une classe de test nommée
ShipTest
dans le répertoiresrc/test/java
de votre projet qui devra vérifier via des tests unitaires la spécification du comportement de la classeShip
.
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class ShipTest {
@Test
public void testTakeAHit(){
= new Ship(3, "Submarine");
Ship submarine assertThat(submarine.getLifePoints()).isEqualTo(3);
.takeAHit();
submarineassertThat(submarine.getLifePoints()).isEqualTo(2);
= new Ship(5, "Carrier");
Ship carrier assertThat(carrier.getLifePoints()).isEqualTo(5);
.takeAHit();
carrier.takeAHit();
carrierassertThat(carrier.getLifePoints()).isEqualTo(3);
}
@Test
public void testTakeAHitWithZeroLifePoint(){
= new Ship(0, "Submarine");
Ship zeroLifeShip assertThat(zeroLifeShip.getLifePoints()).isEqualTo(0);
.takeAHit();
zeroLifeShipassertThat(zeroLifeShip.getLifePoints()).isEqualTo(0);
}
@Test
public void testGetLifePoints(){
= new Ship(3, "Submarine");
Ship submarine assertThat(submarine.getLifePoints()).isEqualTo(3);
= new Ship(5, "Carrier");
Ship carrier assertThat(carrier.getLifePoints()).isEqualTo(5);
}
@Test
public void testHasBeenSunk(){
= new Ship(1, "One life");
Ship oneLife assertThat(oneLife.hasBeenSunk()).isFalse();
.takeAHit();
oneLifeassertThat(oneLife.hasBeenSunk()).isTrue();
= new Ship(3, "Submarine");
Ship submarine for(int index = 0; index < 3; index++) {
assertThat(submarine.hasBeenSunk()).isFalse();
.takeAHit();
submarine}
assertThat(submarine.hasBeenSunk()).isTrue();
}
@Test
public void testToString(){
= new Ship(1, "One life ship");
Ship oneLife assertThat(oneLife.toString()).isEqualTo("One life ship (1 LP)");
= new Ship(3, "Submarine");
Ship submarine assertThat(submarine.toString()).isEqualTo("Submarine (3 LP)");
}
}
Tâche 3 : Créez le type
ShotResult
dans le répertoiresrc/main/java
de votre projet.
public enum ShotResult {
, HIT, SUNK
MISSED}
Tâche 4 : Créez la classe
Cell
dans le répertoiresrc/main/java
de votre projet qui répond aux spécifications ci-dessus. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class Cell {
private Ship ship = null;
private boolean hasBeenShot = false;
/**
* Constructs a cell with no ship.
*/
public Cell(){
}
/**
* Returns the ship belonging to this cell or {@code null} if there is
* no ship in this cell.
*
* @return the ship belonging to this cell
*/
public Ship getShip() {
return ship;
}
/**
* Puts a ship in this cell.
*
* @param ship the ship to be put in this cell
*/
public void setShip(Ship ship) {
this.ship = ship;
}
/**
* Returns {@code true} if this cell has been shot.
* @return {@code true} if this cell has been shot
*/
public boolean hasBeenShot() {
return hasBeenShot;
}
/**
* Shot this cell. The result depends on the state of the cell.
* If the cell has no ship or has already been shot then it returns
* {@code ShotResult.MISSED}. Otherwise, the ship contained in the cell
* takes a hit. If that ship has is sunk then {@code ShotResult.SUNK}
* is returned and {@code ShotResult.HIT} is returned if that ship
* is not sunk.
*
* @return the result of the shot
*/
public ShotResult takeAShot(){
if(hasBeenShot())
return ShotResult.MISSED;
= true;
hasBeenShot if(!hasShip())
return ShotResult.MISSED;
.takeAHit();
shipif(ship.hasBeenSunk())
return ShotResult.SUNK;
return ShotResult.HIT;
}
/**
* Returns {@code true} if this cell contains a ship.
* @return {@code true} if this cell contains a ship
*/
public boolean hasShip() {
return getShip() != null;
}
}
Tâche 5 : Créez une classe de test nommée
CellTest
dans le répertoiresrc/test/java
de votre projet qui devra vérifier via des tests la spécification du comportement de la classeCell
.
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class CellTest {
@Test
void testFirstShotWithNoShipIsMissed(){
= new Cell();
Cell cell assertThat(cell.hasShip()).isFalse();
assertThat(cell.hasBeenShot()).isFalse();
assertThat(cell.takeAShot()).isEqualTo(ShotResult.MISSED);
assertThat(cell.hasBeenShot()).isTrue();
}
@Test
void testFirstShotAtShipWithTwoLifeIsHit(){
= new Cell();
Cell cell = new Ship(2, "Battleship");
Ship battleship .setShip(battleship);
cellassertThat(cell.hasShip()).isTrue();
assertThat(cell.takeAShot()).isEqualTo(ShotResult.HIT);
assertThat(cell.hasBeenShot()).isTrue();
}
@Test
void testFirstShotAtShipWithOneLifeIsSunk(){
= new Cell();
Cell cell = new Ship(1, "OneLifeShip");
Ship oneLifeShip .setShip(oneLifeShip);
cellassertThat(cell.hasShip()).isTrue();
assertThat(cell.takeAShot()).isEqualTo(ShotResult.SUNK);
assertThat(cell.hasBeenShot()).isTrue();
}
@Test
void testTwoShotOnTwoCellsAtShipWithTwoLifeIsSunk(){
= new Cell();
Cell cell1 = new Cell();
Cell cell2 = new Ship(2, "Battleship");
Ship battleship .setShip(battleship);
cell1.setShip(battleship);
cell2assertThat(cell1.takeAShot()).isEqualTo(ShotResult.HIT);
assertThat(cell2.takeAShot()).isEqualTo(ShotResult.SUNK);
}
@Test
void testSecondShotWithNoShipIsMissed(){
= new Cell();
Cell cell assertThat(cell.hasShip()).isFalse();
.takeAShot();
cellassertThat(cell.hasBeenShot()).isTrue();
assertThat(cell.takeAShot()).isEqualTo(ShotResult.MISSED);
}
@Test
void testSecondShotAtShipIsMissed(){
= new Cell();
Cell cell = new Ship(1, "OneLifeShip");
Ship oneLifeShip .setShip(oneLifeShip);
cell.takeAShot();
cellassertThat(cell.hasBeenShot()).isTrue();
assertThat(cell.takeAShot()).isEqualTo(ShotResult.MISSED);
}
@Test
void testSetShip(){
= new Cell();
Cell cell assertThat(cell.getShip()).isNull();
= new Ship(3, "ship");
Ship ship .setShip(ship);
cellassertThat(cell.getShip()).isSameAs(ship);
}
@Test
void testHasShip(){
= new Cell();
Cell cell assertThat(cell.hasShip()).isFalse();
= new Ship(3, "ship");
Ship ship .setShip(ship);
cellassertThat(cell.hasShip()).isTrue();
}
}
Tâche 6 : Créez la classe
Coordinates
dans le répertoiresrc/main/java
de votre projet qui répond aux spécifications ci-dessus. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
import java.util.Objects;
public class Coordinates {
private final int x;
private final int y;
/**
* Construct coordinates in a grid.
*
* @param x the X coordinate of this coordinates
* @param y the Y coordinate of this coordinates
*/
public Coordinates(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Determines whether or not two coordinates are equal. Two instances of
* {@code Coordinates} are equal if the values of their x and y member
* fields are the same.
*
* @param o an object to be compared with this {@code Coordinates}
* @return {@code true} if the object to be compared is an instance
* of {@code Coordinates} and has the same values; false otherwise.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof Coordinates)) return false;
= (Coordinates) o;
Coordinates coordinates return x == coordinates.x && y == coordinates.y;
}
/**
* Returns the X coordinate of this {@code Coordinates}.
* @return the X coordinate of this {@code Coordinates}
*/
public int getX() {
return x;
}
/**
* Returns the Y coordinate of this {@code Coordinates}.
* @return the Y coordinate of this {@code Coordinates}
*/
public int getY() {
return y;
}
/**
* Returns a string representation of this {@code Coordinates}
* with format (x, y).
* @return a string representation of this {@code Coordinates}
*/
@Override
public String toString() {
return "(" + x + ", " + y + ')';
}
/**
* Returns a hash code value for this {@code Coordinates}.
*
* @return a hash code value for this {@code Coordinates}
*/
@Override
public int hashCode() {
return Objects.hash(x, y);
}
/**
* Returns a new {@code Coordinates} with the specified coordinates
* added to this coordinates.
* @param coordinates the coordinates to be added
* @return the added coordinates
*/
public Coordinates add(Coordinates coordinates){
return new Coordinates(this.x + coordinates.x, this.y + coordinates.y);
}
}
Tâche 7 : Créez une classe de test nommée
CoordinatesTest
dans le répertoiresrc/test/java
de votre projet qui devra vérifier via des tests la spécification du comportement de la classeCoordinates
.
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class CoordinatesTest {
@Test
void testGetX(){
assertThat(new Coordinates(0,1).getX()).isEqualTo(0);
assertThat(new Coordinates(1,0).getX()).isEqualTo(1);
}
@Test
void testGetY(){
assertThat(new Coordinates(0,1).getY()).isEqualTo(1);
assertThat(new Coordinates(1,0).getY()).isEqualTo(0);
}
@Test
void testEquals(){
assertThat(new Coordinates(0,1)).isEqualTo(new Coordinates(0,1));
= new Coordinates(0,2);
Coordinates coordinates assertThat(coordinates).isEqualTo(coordinates);
assertThat(coordinates).isNotEqualTo(new Coordinates(0,1));
assertThat(coordinates).isNotEqualTo(new Coordinates(1,2));
}
@Test
void testToString(){
assertThat(new Coordinates(1,2).toString()).isEqualTo("(1, 2)");
assertThat(new Coordinates(0,12).toString()).isEqualTo("(0, 12)");
}
@Test
void testAdd(){
= new Coordinates(1,2).add(new Coordinates(2,2));
Coordinates coordinates1 assertThat(coordinates1.getX()).isEqualTo(3);
assertThat(coordinates1.getY()).isEqualTo(4);
= new Coordinates(1,2).add(new Coordinates(0,0));
Coordinates coordinates2 assertThat(coordinates2.getX()).isEqualTo(1);
assertThat(coordinates2.getY()).isEqualTo(2);
}
}
Tâche 8 : Créez le type
Orientation
dans le répertoiresrc/main/java
de votre projet.
public enum Orientation {
, HORIZONTAL
VERTICAL}
Tâche 9 : Créez la classe
Position
dans le répertoiresrc/main/java
de votre projet qui répond aux spécifications ci-dessus. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class Position {
private final Ship ship;
private final Orientation orientation;
private final Coordinates firstCellCoordinates;
/**
* Construct a position for the specified ship, first cell
* coordinates and orientation.
* @param ship the ship to be positioned
* @param firstCellCoordinates the coordinates of the first
* cell of the positioned ship
* @param orientation the orientation of the positioned ship
*/
public Position(Ship ship, Coordinates firstCellCoordinates, Orientation orientation) {
this.ship = ship;
this.orientation = orientation;
this.firstCellCoordinates = firstCellCoordinates;
}
/**
* Returns an array with all the coordinates of the cells occupied
* by the positioned ship.
* @return the coordinates of the cells occupied by the positioned ship
*/
public Coordinates[] shipCoordinates(){
int length = ship.getLifePoints();
= (orientation == Orientation.HORIZONTAL) ?
Coordinates increment new Coordinates(1,0) : new Coordinates(0, 1);
= firstCellCoordinates;
Coordinates coordinates [] shipCoordinates = new Coordinates[length];
Coordinatesfor(int index = 0; index < length; index++){
[index] = coordinates;
shipCoordinates= coordinates.add(increment);
coordinates }
return shipCoordinates;
}
}
Tâche 10 : Créez une classe de test nommée
PositionTest
dans le répertoiresrc/test/java
de votre projet qui devra vérifier via des tests la spécification du comportement de la classePosition
.
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class PositionTest {
@Test
void testShipCoordinates_whenShipIsHorizontal(){
= new Ship(4, "Ship1");
Ship ship Position position = new Position(ship,new Coordinates(1,2),Orientation.HORIZONTAL);
assertThat(position.shipCoordinates()).containsExactly(new Coordinates(1,2),
new Coordinates(2,2), new Coordinates(3,2), new Coordinates(4,2));
}
@Test
void testShipCoordinates_whenShipIsVertical(){
= new Ship(6, "Ship2");
Ship ship Position position = new Position(ship,new Coordinates(5,4),Orientation.VERTICAL);
assertThat(position.shipCoordinates()).containsExactly(new Coordinates(5,4),
new Coordinates(5,5), new Coordinates(5,6), new Coordinates(5,7),
new Coordinates(5,8), new Coordinates(5,9));
}
}
Tâche 11 : Créez la classe
Grid
dans le répertoiresrc/main/java
de votre projet. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class Grid {
private final int width;
private final int height;
private final Cell[][] cells;
/**
* Construct a grid with the specified dimensions.
*
* @param width the width of the grid to be constructed
* @param height the height of the grid to be constructed
*/
public Grid(int width, int height){
this.width = width;
this.height = height;
= new Cell[width][height];
cells for(int column = 0; column < width; column++){
for(int row = 0; row < height; row++){
[column][row] = new Cell();
cells}
}
}
/**
* Return the width of this grid.
* @return the width of this grid
*/
public int getWidth() {
return width;
}
/**
* Return the height of this grid.
* @return the height of this grid
*/
public int getHeight() {
return height;
}
private Cell getCell(Coordinates coordinates){
return cells[coordinates.getX()][coordinates.getY()];
}
/**
* Returns {@code true} if the grid contains the specified
* coordinates.
* @param coordinates to be tested
* @return {@code true} if the grid contains the specified
* coordinates
*/
public boolean contains(Coordinates coordinates){
return 0 <= coordinates.getX()
&& coordinates.getX() < width
&& 0 <= coordinates.getY()
&& coordinates.getY() < height;
}
/**
* Shoot at the {@code Cell} of the {@code Grid} at the specified
* {@code coordinates} and return the result of the shot.
* If the specified coordinates are outside the range of the grid,
* the call of the method only returns {@code ShotResult.MISSED}.
* For the first shot at some specific coordinates included in
* the {@code Grid}, the result depends on the presence or
* not of a ship at the corresponding {@code Cell}. If there
* are no ship, the result of the shot is always
* {@code ShotResult.MISSED}. If there is a ship the result of
* the shot is {@code ShotResult.SUNK} if it was the last
* life point of the ship and {@code ShotResult.SUNK} otherwise.
* For any subsequent shot, the result of the shot is
* always {@code ShotResult.MISSED}.
*
* @param coordinates the coordinates of the target {@code Cell}
* @return {@code ShotResult.MISSED}, {@code ShotResult.HIT}
* or {@code ShotResult.SUNK} depending on the result of
* the shot.
*/
public ShotResult shootAt(Coordinates coordinates){
if(!contains(coordinates))
return ShotResult.MISSED;
return getCell(coordinates).takeAShot();
}
/**
* Returns {@code true} if the cell at the specified
* coordinates has been shot.
* @param coordinates the coordinates to be tested
* @return {@code true} if the cell at the specified
* coordinates has been shot
*/
public boolean hasBeenShotAt(Coordinates coordinates){
if(!contains(coordinates))
return false;
return getCell(coordinates).hasBeenShot();
}
/**
* Returns {@code true} if the cell at the specified
* coordinates contains a ship.
* @param coordinates the coordinates to be tested
* @return {@code true} if the cell at the specified
* coordinates contains a ship
*/
public boolean hasShipAt(Coordinates coordinates){
if(!contains(coordinates))
return false;
return getCell(coordinates).hasShip();
}
/**
* Put the specified ship in the grid with the specified first
* cell coordinates and orientation.
* @param ship the ship to be put in the grid
* @param firstCell the coordinates of the first cell of the ship
* to be put in the grid
* @param orientation the orientation of the ship
* to be put in the grid
*/
public void putShip(Ship ship, Coordinates firstCell, Orientation orientation){
Position positionedShip = new Position(ship, firstCell, orientation);
for (Coordinates coordinates : positionedShip.shipCoordinates()){
getCell(coordinates).setShip(ship);
}
}
/**
* Returns {@code true} if all the ship contained in this grid have
* been sunk.
* @return {@code true} if all the ship contained in this grid have
* been sunk
*/
public boolean isCompleted(){
for(int column = 0; column < width; column++) {
for (int row = 0; row < height; row++) {
= new Coordinates(column,row);
Coordinates coordinates if(hasShipAt(coordinates) && !hasBeenShotAt(coordinates))
return false;
}
}
return true;
}
}
Tâche 12 : Créez une classe de test nommée
GridTest
dans le répertoiresrc/test/java
de votre projet qui devra vérifier via des tests la spécification du comportement de la classeGrid
.
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class GridTest {
@Test
void testShotOutsideRangeIsMissed(){
= new Grid(3,3);
Grid grid for(int y = 0; y < 3; y++){
= new Ship(3, "Battleship");
Ship battleship = new Coordinates(0,y);
Coordinates coordinates .putShip(battleship, coordinates, Orientation.HORIZONTAL);
grid}
for(int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
assertThat(grid.hasShipAt(new Coordinates(x, y))).isTrue();
}
}
assertThat(grid.shootAt(new Coordinates(-1,-1))).isEqualTo(ShotResult.MISSED);
assertThat(grid.shootAt(new Coordinates(-1,0))).isEqualTo(ShotResult.MISSED);
assertThat(grid.shootAt(new Coordinates(0,-1))).isEqualTo(ShotResult.MISSED);
assertThat(grid.shootAt(new Coordinates(3,3))).isEqualTo(ShotResult.MISSED);
assertThat(grid.shootAt(new Coordinates(3,1))).isEqualTo(ShotResult.MISSED);
assertThat(grid.shootAt(new Coordinates(1,3))).isEqualTo(ShotResult.MISSED);
}
@Test
void testFirstShotWithNoShipIsMissed(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates assertThat(grid.hasShipAt(coordinates)).isFalse();
assertThat(grid.hasBeenShotAt(coordinates)).isFalse();
assertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.MISSED);
assertThat(grid.hasBeenShotAt(coordinates)).isTrue();
}
@Test
void testFirstShotAtShipWithTwoLifeIsHit(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates = new Ship(2, "Battleship");
Ship battleship .putShip(battleship, coordinates, Orientation.HORIZONTAL);
gridassertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.HIT);
assertThat(grid.hasBeenShotAt(coordinates)).isTrue();
}
@Test
void testFirstShotAtShipWithOneLifeIsSunk(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates = new Ship(1, "OneLifeShip");
Ship oneLifeShip .putShip(oneLifeShip, coordinates, Orientation.HORIZONTAL);
gridassertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.SUNK);
assertThat(grid.hasBeenShotAt(coordinates)).isTrue();
}
@Test
void testTwoShotOnTwoCellsAtShipWithTwoLifeIsSunk(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates = new Ship(2, "Battleship");
Ship battleship .putShip(battleship, coordinates, Orientation.HORIZONTAL);
gridassertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.HIT);
assertThat(grid.shootAt(new Coordinates(1,0))).isEqualTo(ShotResult.SUNK);
}
@Test
void testSecondShotWithNoShipIsMissed(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates assertThat(grid.hasShipAt(coordinates)).isFalse();
.shootAt(coordinates);
gridassertThat(grid.hasBeenShotAt(coordinates)).isTrue();
assertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.MISSED);
}
@Test
void testSecondShotAtShipIsMissed(){
= new Grid(3,3);
Grid grid = new Coordinates(0,0);
Coordinates coordinates = new Ship(2, "Battleship");
Ship battleship .putShip(battleship, coordinates, Orientation.HORIZONTAL);
gridassertThat(grid.hasShipAt(coordinates)).isTrue();
.shootAt(coordinates);
gridassertThat(grid.hasBeenShotAt(coordinates)).isTrue();
assertThat(grid.shootAt(coordinates)).isEqualTo(ShotResult.MISSED);
}
@Test
void testGridIsCompleted() {
= new Grid(3, 3);
Grid grid for (int y = 0; y < 2; y++) {
= new Ship(3, "Battleship");
Ship battleship = new Coordinates(0, y);
Coordinates coordinates .putShip(battleship, coordinates, Orientation.HORIZONTAL);
grid}
assertThat(grid.isCompleted()).isFalse();
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 2; y++) {
= new Coordinates(x, y);
Coordinates coordinates .shootAt(coordinates);
grid}
}
assertThat(grid.isCompleted()).isTrue();
}
}
Tâche 13 : Créez la classe
GridPrinter
dans le répertoiresrc/main/java
de votre projet. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class GridPrinter {
private static final char HIT_CHARACTER = 'H';
private static final char MISSED_CHARACTER = 'M';
private static final char BLANK_CHARACTER = ' ';
private final Grid grid;
/**
* Construct a {@code GridPrinter} for the specified grid.
* @param grid the grid to be printed by the {@code GridPrinter}
*/
public GridPrinter(Grid grid) {
this.grid = grid;
}
/**
* Prints the grid associated to this {@code GridPrinter}.
* For instance, a 3x3 grid should be printed as follows
* with H for a hit and M for a miss.
*
* +---+---+---+---+
* | | A | B | C |
* +---+---+---+---+
* | 0 | H | | |
* +---+---+---+---+
* | 1 | | | |
* +---+---+---+---+
* | 2 | | | M |
* +---+---+---+---+
*/
public void printGrid(){
printLine();
printCoordinatesRow();
printLine();
for(int row = 0; row < grid.getHeight(); row++){
printRow(row);
printLine();
}
}
private void printCoordinatesRow(){
System.out.print('|');
printSquare(' ');
for (int column = 0; column < grid.getWidth(); column++){
printSquare((char) ('A' + column));
}
System.out.println();
}
private void printRow(int row){
= new Coordinates(1,0);
Coordinates increment System.out.print("| " + row + " |");
for (Coordinates current = new Coordinates(0, row);
.contains(current); current = current.add(increment)){
gridprintCell(current);
}
System.out.println();
}
private void printSquare(char character){
System.out.print(" " + character + " |");
}
private void printCell(Coordinates coordinates){
if (grid.hasBeenShotAt(coordinates)) {
if(grid.hasShipAt(coordinates))
printSquare(HIT_CHARACTER);
else
printSquare(MISSED_CHARACTER);
}
else
printSquare(BLANK_CHARACTER);
}
private void printLine(){
System.out.print("+");
for (int column = 0; column <= grid.getWidth(); column++){
System.out.print("---+");
}
System.out.println();
}
}
La classe
BattleShipGame
Spécification de la
classe BattleShipGame
La classe représentant l’état du jeu de la bataille navale s’appelle
BattleShipGame
. C’est cette classe qui gérera les tours de
jeu et l’interaction avec l’utilisateur. Ici, on considérera une version
très simplifié du jeu dans lequel il n’y a qu’une grille et le but du
joueur est de couler tous les bateaux en le minimum de coups.
Description des éléments de la classe (un exemple de partie est disponible à la fin de la planche de TP):
- l’attribut
turnCount
: le nombre de tours de jeu; - l’attribut
gridPrinter
: l’afficheur de la grille; - l’attribut
grid
: la grille du jeu; - l’attribut
scanner
: le lecteur pour l’entrée standard, à initialiser avecnew Scanner(System.in)
(Javadoc de Scanner); - le constructeur
BattleShipGame(grid : Grid)
qui initialise tous les attributs à partir de la grille spécifiée; - la méthode
playGame
: fait jouer une partie, c’est-à-dire fait jouer des tours jusqu’à que la grille soit complétée; - la méthode
playTurn
: fait jouer un tour, affiche le nombre de tours, collecte les coordonnées entrées par le joueur, puis affiche un message
- la méthode
printTurnNumberMessage
affiche le nombre de tours; - la méthode
printShotResultMessage
affiche le résultat du tir (You sunk a ship.
,You hit a ship.
ouYou missed.
); - la méthode
collectCoordinates
affiche un message demandant les coordonnées à l’utilisateur puis récupère celle-ci. On utilisera le formatB3
(une lettre deA
àJ
suivi d’un chiffre de0
à9
) qu’on pourra récupérer avecscanner.next("\\p{Upper}\\d")
, cela nous donnera une chaîne de 2 caractère à partir de laquelle on déduira des coordonnées ; - la méthode
printWinningMessage
affiche le message de victoire.
Tâches
Tâche 14 : Créez la classe
BattleShipGame
dans le répertoiresrc/main/java
de votre projet. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
import java.util.Scanner;
import java.util.regex.Pattern;
public class BattleShipGame {
private int turnCount = 0;
private final GridPrinter gridPrinter;
private final Grid grid;
private final Scanner scanner = new Scanner(System.in);
/**
* Constructs a {@code BattleShipGame} with the specified
* grid as the board of the game.
*
* @param grid the grid used by the constructed
* {@code BattleShipGame}
*/
public BattleShipGame(Grid grid) {
this.grid = grid;
this.gridPrinter = new GridPrinter(grid);
}
/**
* Launch this game.
*/
public void playGame(){
while (!grid.isCompleted()){
playTurn();
}
printWinningMessage();
}
private void printWinningMessage() {
System.out.println("You have won in " + turnCount + " turns.");
}
private void playTurn(){
.printGrid();
gridPrinterprintTurnNumberMessage();
= collectCoordinates();
Coordinates coordinates = grid.shootAt(coordinates);
ShotResult result printShotResultMessage(result);
++;
turnCount}
private void printTurnNumberMessage() {
System.out.println("Turn number " + turnCount);
}
private static void printShotResultMessage(ShotResult result) {
switch(result){
case SUNK -> System.out.println("You sunk a ship.");
case HIT -> System.out.println("You hit a ship.");
case MISSED -> System.out.println("You missed.");
}
}
private Coordinates collectCoordinates() {
System.out.println("Enter coordinates");
String input = scanner.next("\\p{Upper}\\d");
int xCoordinates = input.charAt(0) - 'A';
int yCoordinates = input.charAt(1) - '0';
return new Coordinates(xCoordinates, yCoordinates);
}
}
Tâche 15 : Créez une classe
BattleShipApp
dans le répertoiresrc/main/java
de votre projet. Votre code devra donner la Javadoc pour toutes les méthodes publiques de la classe.
public class BattleShipApp {
/**
* Starts a solo Battleship game with a 5x3 grid and a unique ship
* of length 3 in the first line of the grid.
*
* @param args the parameters of the command which are ignored
*/
public static void main(String[] args){
= new Grid(5,3);
Grid grid .putShip(new Ship(3, "Battleship"),
gridnew Coordinates(0,0), Orientation.HORIZONTAL);
= new BattleShipGame(grid);
BattleShipGame battleShipGame .playGame();
battleShipGame}
}
Tâche 16 : Donnez le diagramme de toutes les classes du projet en indiquant les types de relations entre les classes et leur multiplicité. Il n’est pas nécessaire de redonner les attributs et les méthodes des classes.