Improved MVC model

This commit is contained in:
Quentin Legot 2021-04-10 12:42:15 +02:00
parent dfe1c2ff72
commit 0546fa73bc
11 changed files with 234 additions and 205 deletions

View File

@ -1,12 +1,12 @@
package battleship; package battleship;
import battleship.model.Game; import battleship.model.Game;
import battleship.model.player.AbstractPlayer;
import battleship.model.player.Human; import battleship.model.player.Human;
import battleship.model.player.Player;
import battleship.model.player.Random; import battleship.model.player.Random;
import battleship.utils.Pair; import battleship.utils.Pair;
import battleship.view.AbstractView;
import battleship.view.Terminal; import battleship.view.Terminal;
import battleship.view.View;
import battleship.view.Window; import battleship.view.Window;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -15,7 +15,7 @@ import java.util.NoSuchElementException;
public class Main { public class Main {
public static View view; public static AbstractView view;
public static Game game; public static Game game;
public static void main(String[] args) { public static void main(String[] args) {
@ -35,13 +35,13 @@ public class Main {
} }
private static void parseArgs(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { private static void parseArgs(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Player[] players = new Player[2]; AbstractPlayer[] players = new AbstractPlayer[2];
ArrayList<Pair<String, Class<? extends Player>>> playerClass = new ArrayList<>(2); ArrayList<Pair<String, Class<? extends AbstractPlayer>>> playerClass = new ArrayList<>(2);
playerClass.add(new Pair<>("human", Human.class)); playerClass.add(new Pair<>("human", Human.class));
playerClass.add(new Pair<>("random", Random.class)); playerClass.add(new Pair<>("random", Random.class));
if(args.length >= 2) { if(args.length >= 2) {
for(int i = 0; i < 2; ++i) { for(int i = 0; i < 2; ++i) {
for (Pair<String, Class<? extends Player>> pair : playerClass) { for (Pair<String, Class<? extends AbstractPlayer>> pair : playerClass) {
if(args[i].equalsIgnoreCase(pair.getLeft())) { if(args[i].equalsIgnoreCase(pair.getLeft())) {
players[i] = pair.getRight().getDeclaredConstructor().newInstance(); players[i] = pair.getRight().getDeclaredConstructor().newInstance();
} }

View File

@ -0,0 +1,7 @@
package battleship.model;
// TODO: 10/04/2021
public class Board {
}

View File

@ -1,17 +1,19 @@
package battleship.model; package battleship.model;
import battleship.model.player.AbstractPlayer;
import battleship.model.player.Player; import battleship.model.player.Player;
import battleship.utils.Pair; import battleship.utils.Pair;
import battleship.utils.Triplet; import battleship.utils.Triplet;
import battleship.view.View; import battleship.view.AbstractView;
import java.util.Random;
public class Game { public class Game {
public Player[] players; public Player[] players;
public Player currentPlayer; public Player currentPlayer;
private final int[] ships = { 5, 4, 3, 3, 2};
public Game(Player[] players) { public Game(AbstractPlayer[] players) {
this.players = players; this.players = players;
this.currentPlayer = players[0]; this.currentPlayer = players[0];
players[0].setId(1); players[0].setId(1);
@ -33,17 +35,17 @@ public class Game {
public void checkDrownedShips(){ public void checkDrownedShips(){
Player otherPlayer = getOtherPlayer(); Player otherPlayer = getOtherPlayer();
for(Ship ship : currentPlayer.getShips()){ for(Ship ship : currentPlayer.ships){
if(!ship.isDrown()) if(!ship.isDrown())
otherPlayer.updateIsDrown(ship); otherPlayer.updateIsDrown(ship);
} }
} }
public Player getWinner(){ public Player getWinner(){
Ship remainingShip = players[0].getShips().parallelStream().filter(ship -> !ship.isDrown()).findFirst().orElse(null); Ship remainingShip = players[0].ships.parallelStream().filter(ship -> !ship.isDrown()).findFirst().orElse(null);
if(remainingShip == null) if(remainingShip == null)
return players[1]; return players[1];
remainingShip = players[1].getShips().parallelStream().filter(ship -> !ship.isDrown()).findFirst().orElse(null); remainingShip = players[1].ships.parallelStream().filter(ship -> !ship.isDrown()).findFirst().orElse(null);
if(remainingShip == null) if(remainingShip == null)
return players[1]; return players[1];
return null; return null;
@ -52,7 +54,7 @@ public class Game {
public void move(Pair<Integer,Integer> move){ public void move(Pair<Integer,Integer> move){
boolean bool = false; boolean bool = false;
Player otherPlayer = getOtherPlayer(); Player otherPlayer = getOtherPlayer();
for (Ship ship : otherPlayer.getShips()) { for (Ship ship : otherPlayer.ships) {
for(Pair<Integer,Integer> pair : ship.getCoordsArray()){ for(Pair<Integer,Integer> pair : ship.getCoordsArray()){
if ((pair.getRight().equals(move.getRight())) && (pair.getLeft().equals(move.getLeft()))) { if ((pair.getRight().equals(move.getRight())) && (pair.getLeft().equals(move.getLeft()))) {
bool = true; bool = true;
@ -63,7 +65,7 @@ public class Game {
currentPlayer.addMove(new Triplet<>(move, bool)); currentPlayer.addMove(new Triplet<>(move, bool));
} }
public void Play(View view){ public void Play(AbstractView view){
view.setShips(players[0]); view.setShips(players[0]);
view.setShips(players[1]); view.setShips(players[1]);
Player winner = null; Player winner = null;
@ -78,4 +80,14 @@ public class Game {
} }
public void placeShipRandomly(Player player) {
Random rand = new Random();
for(int i : player.ShipSize) {
Ship ship = new Ship(new Pair<>(-1, -1), i, Direction.DEFAULT);
while(!player.setShips(ship)) {
ship = new Ship(new Pair<>(rand.nextInt(10), rand.nextInt(10)), i, Direction.values()[rand.nextInt(Direction.values().length)]);
}
}
}
} }

View File

@ -0,0 +1,82 @@
package battleship.model.player;
import battleship.model.Direction;
import battleship.model.Ship;
import battleship.utils.Pair;
import battleship.utils.Triplet;
import java.util.ArrayList;
public abstract class AbstractPlayer implements Player {
public int id;
public boolean setShips(Ship ship) {
if(ship.getDirection() == Direction.DEFAULT)
return false;
for(int i = 0; i < ship.getSize(); i++){
int x = ship.getCoords().getLeft() + i * ship.getDirection().getDirection().getLeft();
int y = ship.getCoords().getRight()+ i * ship.getDirection().getDirection().getRight();
if(x > 9 || x < 0 || y > 9 || y < 0)
return false;
for(Ship ship1 : this.ships) {
for (int j = 0; j < ship1.getSize(); j++) {
int x1 = ship1.getCoords().getLeft() + i * ship1.getDirection().getDirection().getLeft();
int y1 = ship1.getCoords().getRight() + i * ship1.getDirection().getDirection().getRight();
if (x1 == x && y1 == y)
return false;
}
}
}
this.ships.add(ship);
return true;
}
/**
* La methode retourne son objet afin d'avoir la possibilité de faire Player.addMove().addMove().etc...
* @param move
* @return Player
*/
public Player addMove(Triplet<Integer,Integer,Boolean> move){
moves.add(move);
return this;
}
public void updateIsDrown(Ship ship) {
int cpt = 0;
for(Triplet<Integer,Integer,Boolean> move : moves){
for(int i = 1; i <= ship.getSize(); i++){
int x = ship.getCoords().getLeft() + i * ship.getDirection().getDirection().getLeft();
int y = ship.getCoords().getRight()+ i * ship.getDirection().getDirection().getRight();
if(move.getLeft() == x && move.getMiddle() == y){
cpt += 1;
break;
}
}
}
if(cpt == ship.getSize())
ship.setDrown();
}
public ArrayList<Pair<Integer,Integer>> validMoves() {
ArrayList<Pair<Integer,Integer>> validMovesList = new ArrayList<>();
for(int x = 0; x < 10; x++){
for(int y = 0; y < 10; y++) {
Pair<Integer, Integer> coords = new Pair<>(x,y);
if(!moves.contains(new Triplet<>(coords, true)) || !moves.contains(new Triplet<>(coords, false))){
validMovesList.add(new Pair<>(x,y));
}
}
}
return validMovesList;
}
public void setId(int i) {
id = i;
}
public int getId() {
return id;
}
}

View File

@ -6,7 +6,7 @@ import battleship.view.Terminal;
import java.util.Scanner; import java.util.Scanner;
public class Human extends Player { public class Human extends AbstractPlayer {

View File

@ -1,104 +1,28 @@
package battleship.model.player; package battleship.model.player;
import battleship.model.Direction;
import battleship.model.Ship; import battleship.model.Ship;
import battleship.utils.Pair; import battleship.utils.Pair;
import battleship.utils.Triplet; import battleship.utils.Triplet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Random;
public abstract class Player { public interface Player {
protected ArrayList<Ship> ships = new ArrayList<>(); ArrayList<Ship> ships = new ArrayList<>();
protected ArrayList<Triplet<Integer,Integer,Boolean>> moves = new ArrayList<>(); ArrayList<Triplet<Integer,Integer,Boolean>> moves = new ArrayList<>();
protected int id; int[] ShipSize = { 5, 4, 3, 3, 2};
protected final static int[] bato = { 5, 4, 3, 3, 2};
public boolean setShips(Ship ship) { Pair<Integer,Integer> chooseMove();
if(ship.getDirection() == Direction.DEFAULT)
return false;
for(int i = 0; i < ship.getSize(); i++){
int x = ship.getCoords().getLeft() + i * ship.getDirection().getDirection().getLeft();
int y = ship.getCoords().getRight()+ i * ship.getDirection().getDirection().getRight();
if(x > 9 || x < 0 || y > 9 || y < 0)
return false;
for(Ship ship1 : this.ships) {
for (int j = 0; j < ship1.getSize(); j++) {
int x1 = ship1.getCoords().getLeft() + i * ship1.getDirection().getDirection().getLeft();
int y1 = ship1.getCoords().getRight() + i * ship1.getDirection().getDirection().getRight();
if (x1 == x && y1 == y)
return false;
}
}
}
this.ships.add(ship);
return true;
}
/** boolean setShips(Ship ship);
* La methode retourne son objet afin d'avoir la possibilité de faire Player.addMove().addMove().etc...
* @param move
* @return Player
*/
public Player addMove(Triplet<Integer,Integer,Boolean> move){
moves.add(move);
return this;
}
public void updateIsDrown(Ship ship) { int getId();
int cpt = 0;
for(Triplet<Integer,Integer,Boolean> move : moves){
for(int i = 1; i <= ship.getSize(); i++){
int x = ship.getCoords().getLeft() + i * ship.getDirection().getDirection().getLeft();
int y = ship.getCoords().getRight()+ i * ship.getDirection().getDirection().getRight();
if(move.getLeft() == x && move.getMiddle() == y){
cpt += 1;
break;
}
}
}
if(cpt == ship.getSize())
ship.setDrown();
}
public ArrayList<Ship> getShips(){
return this.ships;
}
public ArrayList<Triplet<Integer,Integer,Boolean>> getMoves(){ void updateIsDrown(Ship ship);
return this.moves;
} Player addMove(Triplet<Integer,Integer,Boolean> move);
public abstract Pair<Integer,Integer> chooseMove();
public ArrayList<Pair<Integer,Integer>> validMoves() {
ArrayList<Pair<Integer,Integer>> validMovesList = new ArrayList<>();
for(int x = 0; x < 10; x++){
for(int y = 0; y < 10; y++) {
Pair<Integer, Integer> coords = new Pair<>(x,y);
if(!moves.contains(new Triplet<>(coords, true)) || !moves.contains(new Triplet<>(coords, false))){
validMovesList.add(new Pair<>(x,y));
}
}
}
return validMovesList;
}
public void setId(int i){
id = i;
}
public int getId() {
return id;
}
public void placeShipRandomly() {
Random rand = new Random();
for(int i : bato) {
Ship ship = new Ship(new Pair<>(-1, -1), i, Direction.DEFAULT);
while(!setShips(ship)) {
ship = new Ship(new Pair<>(rand.nextInt(10), rand.nextInt(10)), i, Direction.values()[rand.nextInt(Direction.values().length)]);
}
}
}
} }

View File

@ -2,7 +2,7 @@ package battleship.model.player;
import battleship.utils.Pair; import battleship.utils.Pair;
public class Random extends Player { public class Random extends AbstractPlayer {
@Override @Override
public Pair<Integer,Integer> chooseMove() { public Pair<Integer,Integer> chooseMove() {

View File

@ -0,0 +1,98 @@
package battleship.view;
import battleship.model.Game;
import battleship.model.Ship;
import battleship.model.player.Player;
import battleship.utils.Pair;
import battleship.utils.Triplet;
import java.util.ArrayList;
public abstract class AbstractView implements View{
protected Game game;
public AbstractView(Game game) {
this.game = game;
}
@Override
public String toString() {
// String chain = "A vous de joueur "+game.currentPlayer.toString()+ "\n+ - - - - - - - - - - +\n";
String chain = "";
for(int u = 0; u < 2; ++u) {
Player player = game.players[u];
ArrayList<Ship> ships = game.players[u].ships;
chain += "Player " + (u + 1) + " :\n";
chain += "+ - - - - - - - - - - +\n";
for(int x = 0; x < 10; ++x) {
chain += "|";
for(int y = 0; y < 10; ++y) {
Pair<Integer, Integer> pair = new Pair<>(x, y);
boolean isPosition = false;
for(Ship ship : ships) {
if(isShipPosition(ship, pair)) {
isPosition = true;
int result = isPositionDrowned(game.players[u == 0 ? 1 : 0], ship, pair);
if(result == 1) {
chain += " X";
} else if (result == 2){
chain += " !";
} else {
chain += " .";
}
break;
}
}
if(!isPosition) {
if(isPositionDrowned(game.players[u == 0 ? 1 : 0], pair) == 2) {
chain += " ?";
} else {
chain += " _";
}
}
}
chain += " |\n";
}
chain += "+ - - - - - - - - - - +\n";
}
return chain;
}
private boolean isShipPosition(Ship ship, Pair<Integer, Integer> boardsCoords) {
if(ship.getCoords().equals(boardsCoords))
return true;
for(int a = 0; a < ship.getSize(); ++a) {
if(new Pair<>(ship.getCoords().getLeft() + a * ship.getDirection().getDirection().getLeft(), ship.getCoords().getRight() + a * ship.getDirection().getDirection().getRight()).equals(boardsCoords)) {
return true;
}
}
return false;
}
private int isPositionDrowned(Player other, Pair<Integer, Integer> pair) {
for(Triplet<Integer, Integer, Boolean> move : other.moves) {
if(pair.getLeft().equals(move.getLeft()) && pair.getRight().equals(move.getMiddle())) {
return 2;
}
}
return 0;
}
/**
*
* @param other other than the current player
* @param ship check if this ship at this position is touch
* @param pair coords
* @return 1 if ship fully drowned, 2 if only damaged, 0 if not
*/
private int isPositionDrowned(Player other, Ship ship, Pair<Integer, Integer> pair) {
if(ship.isDrown())
return 1;
return isPositionDrowned(other, pair);
}
}

View File

@ -9,7 +9,7 @@ import battleship.utils.Pair;
import java.util.Scanner; import java.util.Scanner;
public class Terminal extends View { public class Terminal extends AbstractView {
public static Scanner scanner = new Scanner(System.in); public static Scanner scanner = new Scanner(System.in);
@ -23,7 +23,7 @@ public class Terminal extends View {
int x, y; int x, y;
String dir; String dir;
if(player instanceof Human) { if(player instanceof Human) {
for(int i : ships) { for(int i : shipsSize) {
boolean valid = false; boolean valid = false;
Ship ship = new Ship(new Pair<>(-1, -1), i, Direction.DEFAULT); Ship ship = new Ship(new Pair<>(-1, -1), i, Direction.DEFAULT);
while (!player.setShips(ship)) { while (!player.setShips(ship)) {
@ -54,7 +54,7 @@ public class Terminal extends View {
} }
} else { } else {
// Random // Random
player.placeShipRandomly(); game.placeShipRandomly(player);
} }

View File

@ -1,107 +1,14 @@
package battleship.view; package battleship.view;
import battleship.model.Game;
import battleship.model.Ship;
import battleship.model.player.Player; import battleship.model.player.Player;
import battleship.utils.Pair;
import battleship.utils.Triplet;
import java.awt.Graphics; public interface View {
import java.awt.*;
import java.util.ArrayList;
public abstract class View { int[] shipsSize = { 5, 4, 3, 3, 2};
void setShips(Player player);
protected final Game game; void displayBoard();
protected final int[] ships = { 5, 4, 3, 3, 2};
public View(Game game) { void displayWinner(Player winner);
this.game = game;
}
public abstract void setShips(Player player);
public abstract void displayBoard();
@Override
public String toString() {
// String chain = "A vous de joueur "+game.currentPlayer.toString()+ "\n+ - - - - - - - - - - +\n";
String chain = "";
for(int u = 0; u < 2; ++u) {
Player player = game.players[u];
ArrayList<Ship> ships = game.players[u].getShips();
chain += "Player " + (u + 1) + " :\n";
chain += "+ - - - - - - - - - - +\n";
for(int x = 0; x < 10; ++x) {
chain += "|";
for(int y = 0; y < 10; ++y) {
Pair<Integer, Integer> pair = new Pair<>(x, y);
boolean isPosition = false;
for(Ship ship : ships) {
if(isShipPosition(ship, pair)) {
isPosition = true;
int result = isPositionDrowned(game.players[u == 0 ? 1 : 0], ship, pair);
if(result == 1) {
chain += " X";
} else if (result == 2){
chain += " !";
} else {
chain += " .";
}
break;
}
}
if(!isPosition) {
if(isPositionDrowned(game.players[u == 0 ? 1 : 0], pair) == 2) {
chain += " ?";
} else {
chain += " _";
}
}
}
chain += " |\n";
}
chain += "+ - - - - - - - - - - +\n";
}
return chain;
}
private boolean isShipPosition(Ship ship, Pair<Integer, Integer> boardsCoords) {
if(ship.getCoords().equals(boardsCoords))
return true;
for(int a = 0; a < ship.getSize(); ++a) {
if(new Pair<>(ship.getCoords().getLeft() + a * ship.getDirection().getDirection().getLeft(), ship.getCoords().getRight() + a * ship.getDirection().getDirection().getRight()).equals(boardsCoords)) {
return true;
}
}
return false;
}
private int isPositionDrowned(Player other, Pair<Integer, Integer> pair) {
for(Triplet<Integer, Integer, Boolean> move : other.getMoves()) {
if(pair.getLeft().equals(move.getLeft()) && pair.getRight().equals(move.getMiddle())) {
return 2;
}
}
return 0;
}
/**
*
* @param other other than the current player
* @param ship check if this ship at this position is touch
* @param pair coords
* @return 1 if ship fully drowned, 2 if only damaged, 0 if not
*/
private int isPositionDrowned(Player other, Ship ship, Pair<Integer, Integer> pair) {
if(ship.isDrown())
return 1;
return isPositionDrowned(other, pair);
}
public abstract void displayWinner(Player winner);
} }

View File

@ -3,11 +3,10 @@ package battleship.view;
import battleship.model.Game; import battleship.model.Game;
import battleship.model.player.Player; import battleship.model.player.Player;
import java.awt.Graphics;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
public class Window extends View { public class Window extends AbstractView {
private JFrame frame; private JFrame frame;