<file_sep>package com.excilys.formation.battleships.android.ui.ships;

import com.excilys.formation.battleships.ship.Submarine;

import java.util.HashMap;
import java.util.Map;

import battleships.formation.excilys.com.battleships.R;

/**
 * Created by tiberiodarferreira on 06/10/2016.
 */

public class DrawableSubmarine extends Submarine implements DrawableShip {
    public DrawableSubmarine(Orientation orientation){
        super(orientation);
    }
    public DrawableSubmarine(){
        super(Orientation.NORTH);
    }
    static final Map<Orientation, Integer> DRAWABLES = new HashMap<>();
    static {
        // The code inside here will be executed just once when the class is loaded
        // So all the changes here are shared with the "brother" classes
        DRAWABLES.put(Orientation.NORTH,  R.drawable.submarine_s);
        DRAWABLES.put(Orientation.SOUTH,  R.drawable.submarine_n);
        DRAWABLES.put(Orientation.WEST,  R.drawable.submarine_w);
        DRAWABLES.put(Orientation.EAST,  R.drawable.submarine_e);
    }

    @Override
    public int getDrawable() {
        return DRAWABLES.get(this.getOrientation());
    }
}
<file_sep>package com.excilys.formation.battleships.ship;

/**
 * Created by tiberiodarferreira on 23/09/2016.
 */
public class Submarine extends AbstractShip {
    public Submarine(){
        super("", ShipType.SUBMARINE, null, 3);
    }
    public Submarine(Orientation orientation){
        super("", ShipType.SUBMARINE, orientation, 3);
    }
}
<file_sep>package com.excilys.formation.battleships;
import com.excilys.formation.battleships.ship.AbstractShip;
import com.excilys.formation.battleships.ship.ShipState;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by tiberiodarferreira on 16/09/2016.
 */
public class Board implements IBoard{
    private int size;
    private Boolean[][] frappes;
    private ShipState[][] navire;
    private String name;
    private Board(String name, int size){
        this.name = name;
        if (size>20){
            System.out.println("Tableau trop grand! Limit = 20");
        }else{
            this.size = size;
        }
        frappes = new Boolean[size][size];
        navire = new ShipState[size][size];
        for (int i = 0; i<size; i++){
            for (int j = 0; j<size; j++){
                navire[i][j] = new ShipState();
            }
        }
    }

    String getName(){
        return name;
    }

    public Board(String name){
        this(name, 10);
    }

    /**
     Outputs the tables to the screen
     */
    void printTableau(){
        System.out.print("Navires:");
        for (int i=0; i<1 + 2*size; i++) {
            System.out.print(" ");
        }


        System.out.println("Frappes:");
        System.out.print("\t");
        for (char ch = 'A'; ch<(size+'A'); ch++){
            System.out.print( " " + ch);
        }


        System.out.print("\t\t");
        for (char ch = 'A'; ch<(size+'A'); ch++){
            System.out.print( " " + ch);
        }
        System.out.println();
        for (int i = 0; i < size; i++){
            for (int un_deux=0; un_deux<2; un_deux++) { // 0 = navire 1 = frappes
                System.out.print(i);
                System.out.print('\t');
                for (int i_nested1 = 0; i_nested1 < size; i_nested1++) {
                    if (un_deux == 1) {
                        if (frappes[i_nested1][i] == null) {
                            System.out.print(" .");
                        } else if(!frappes[i_nested1][i]) {
                            System.out.print(ColorUtil.colorize(" X", ColorUtil.Color.WHITE));
                        } else if(frappes[i_nested1][i]) {
                            System.out.print(ColorUtil.colorize(" X", ColorUtil.Color.RED));
                        }
                    }else{
                        if(navire[i_nested1][i].isStruck()) {
                            System.out.print(ColorUtil.colorize(" " + navire[i_nested1][i].getShipAsChar(), ColorUtil.Color.RED));
                        }else {
                            System.out.print(" " + navire[i_nested1][i].getShipAsChar());
                        }
                    }
                }
                System.out.print('\t');

            }
            System.out.println();
        }
    }

    public int getSize() {
        return size;
    }

    @Override
    public boolean hasShip(int x, int y) {
        return (navire[x][y].isShip());
    }


    /**
     @param hit True if hit something, false if missed
     @param x The coordinate x of the hit
     @param y The coordinate y of the hit
     */
    @Override
    public void setHit(boolean hit, int x, int y) {
        if (!isInsideGrid(x, y)){
            System.out.println("Invalid location: x = " + x + " y= " + y);
            return;
        }
        frappes[x][y] = hit;
    }


    /**
     @param x The coordinate x of the hit
     @param y The coordinate y of the hit
     @return True if there is a hit (!=miss) in the coordinates, false if there is not
     */
    @Override
    public Boolean getHit(int x, int y) {
        if (!isInsideGrid(x, y)){
            System.out.println("Invalid location: x = " + x + " y= " + y);
            return false;
        }
        return frappes[x][y];
    }


    /**
     @param x The coordinate x of the hit
     @param y The coordinate y of the hit
     @return A Hit representing what was hit at (x, y)
     */
    public Hit sendHit(int x, int y){
        if (!isInsideGrid(x, y)){
            System.out.println("Invalid location: x = " + x + " y= " + y);
            return null;
        }
        navire[x][y].addStrike();
        if(!navire[x][y].isShip()){
            return Hit.fromInt(-1);
        }else if(navire[x][y].isSunk()) {
            switch (navire[x][y].getShip().getShipType()) {
                case BATTLESHIP:
                    return Hit.fromInt(4);
                case DESTROYER:
                    return Hit.fromInt(2);
                case SUBMARINE:
                    return Hit.fromInt(3);
                case CARRIER:
                    return Hit.fromInt(5);
                default:
                    System.out.println("Holy intervention is preventing this program from working properly.");
                    return null;
            }
        }else{
            return Hit.fromInt(-2);
        }
    }



    /**
     @param ship The ship to be put
     @param x The coordinate x where to put the ship
     @param y The coordinate y where to put the ship
     */
    @Override
    public int putShip(AbstractShip ship, int x, int y) {
        if (!isInsideGrid(x, y)){
            System.out.println("Invalid location: x = " + x + " y= " + y);
            return -1;
        }
        assert ship.getOrientation() != null : "Ship with null orientation being added!";

        int x_temp = x;
        int y_temp = y;
        List<AbstractShip.Location> shipLocation = new ArrayList<>();
        for (int i=0; i < ship.getLength(); i++) {
            AbstractShip.Location Loc = new AbstractShip.Location(x_temp, y_temp);
            shipLocation.add(Loc);
            if (ship.getOrientation() == AbstractShip.Orientation.EAST) {
                x_temp += 1;
            } else if (ship.getOrientation() == AbstractShip.Orientation.WEST) {
                x_temp -= 1;
            } else if (ship.getOrientation() == AbstractShip.Orientation.NORTH) {
                y_temp -= 1;
            } else if (ship.getOrientation() == AbstractShip.Orientation.SOUTH) {
                y_temp += 1;
            }
        }
        for (AbstractShip.Location Loc : shipLocation){
            if (!isInsideGrid(Loc.getX(), Loc.getY())){
                System.out.println("This puts the ship outside the board!");
                return -1;
            }
            if(hasShip(Loc.getX(), Loc.getY())){
                System.out.println("Cannot put ship there, there is already one at X = " + Loc.getX() + " Y = " + Loc.getY());
                return -1;
            }
        }
        for (AbstractShip.Location Loc : shipLocation){
            System.out.println("X = " + Loc.getX() + " Y= " + Loc.getY());
            navire[Loc.getX()][Loc.getY()] = new ShipState(ship);
        }
        printTableau();
        return 1;
    }
    /**
     @param x Coordinate x
     @param y Coordinate y
     @return True if the coordinates are of a position already hit
     */
    public boolean alreadyHit(int x, int y){
        if (!isInsideGrid(x, y)){
            System.out.println("Invalid location: x = " + x + " y= " + y);
            return false;
        }
        return navire[x][y].isStruck();
    }

    /**
     @param x Coordinate x
     @param y Coordinate y
     @return True if the coordinates are inside the game table, false otherwise
     */
    private boolean isInsideGrid(int x, int y){
        return !((x < 0 || y < 0) || ((x > size - 1 || y > size - 1)));
    }
}


<file_sep>package com.excilys.formation.battleships.ship;

/**
 * Created by tiberiodarferreira on 23/09/2016.
 */
public class Destroyer extends AbstractShip {
    public Destroyer(){
        super("", ShipType.DESTROYER, null, 2);
    }
    public Destroyer(Orientation orientation){
        super("", ShipType.DESTROYER, orientation, 2);
    }
}
<file_sep>package com.excilys.formation.battleships.android.ui.ships;

/**
 * Just an interface to make sure all ships can be drawn on the screen
 */
public interface DrawableShip {
    int getDrawable();
}
<file_sep>package com.excilys.formation.battleships.ship;

/**
 * Created by tiberiodarferreira on 23/09/2016.
 */
public class Carrier extends AbstractShip {
    public Carrier(){
        super("", ShipType.CARRIER, null, 5);
    }
    public Carrier(Orientation orientation){
        super("", ShipType.CARRIER, orientation, 5);
    }
}
<file_sep>package com.excilys.formation.battleships.ship;

/**
 * Created by tiberiodarferreira on 23/09/2016.
 */
public class Battleship extends AbstractShip {
    public Battleship(){
        super("", ShipType.BATTLESHIP, null, 4);
    }
    public Battleship(Orientation orientation){
        super("", ShipType.BATTLESHIP, orientation, 4);
    }

}
<file_sep>package com.excilys.formation.battleships;


import com.excilys.formation.battleships.ship.AbstractShip;
import com.excilys.formation.battleships.Board;

import java.io.Serializable;
import java.util.List;

public class Player {
    protected Board board;
    private Board opponentBoard;
    public int destroyedCount;
    protected AbstractShip[] ships;
    public boolean lose;
    private String name;

    public Player(String name, Board board, Board opponentBoard, List<AbstractShip> ships) {
        this.name = name;
        this.board = board;
        this.ships = ships.toArray(new AbstractShip[0]);
        this.opponentBoard = opponentBoard;
    }

    public String getName(){
        return this.name;
    }

    /**
     * Read keyboard input to get ships coordinates. Place ships on given coordenates.
     * Attempts to put the ships in pos x y
     * @param x the x position
     * @param y the y position
     * Is not used in this Android version
     */
    public void putShips(int x, int y) {
        int i = 0;
        boolean done = false;
        do {
            AbstractShip s = ships[i];
            System.out.println("Place your " + s.getLabel());
            InputHelper.ShipInput res = InputHelper.readShipInput();
            AbstractShip.Orientation orientation;
            switch (res.orientation) {
                case "n":
                    orientation = AbstractShip.Orientation.NORTH;
                    break;
                case "s":
                    orientation = AbstractShip.Orientation.SOUTH;
                    break;
                case "e":
                    orientation = AbstractShip.Orientation.EAST;
                    break;
                case "o":
                    orientation = AbstractShip.Orientation.WEST;
                    break;
                default:
                    System.out.println("Not a valid orientation");
                    return;
            }
            s.setOrientation(orientation);
            try {
                board.putShip(s, res.x, res.y);
                ++i;
                done = i == ships.length;
            } catch(Exception e) {
                System.err.println("Impossible de placer le navire a cette position");
                System.out.println(e);
            }
            board.printTableau();

        } while (!done);
    }
    /**
     * Asks the players for coordinates and sends an Hit on opponents table on those coordinates
     * @param coords Variable which should be an int[2] and which will be populated with the
     * coordinates of where the shot was sent
     * @return hit which contains the information about the success of the shot
     */
    public Hit sendHit(int[] coords) {
        boolean done = false;
        Hit hit = null;
        do {
            InputHelper.CoordInput hitInput = InputHelper.readCoordInput();
                hit = opponentBoard.sendHit(hitInput.x, hitInput.y);
                coords[0] = hitInput.x;
                coords[1] = hitInput.y;
                if (hit != null) {
                    done = true;
                }
        } while (!done);
        return hit;
    }

    public AbstractShip[] getShips() {
        return ships;
    }

    public void setShips(AbstractShip[] ships) {
        this.ships = ships;
    }
}<file_sep>package com.excilys.formation.battleships.ship;

/**
 * Created by tiberiodarferreira on 23/09/2016.
 */
public class ShipState {
    private AbstractShip ship;
    private boolean struck = false;
    public ShipState(AbstractShip ship){
        this.ship = ship;
    }
    public ShipState(){
        this.ship = null;
    }
    public boolean isShip(){
        return !(ship==null);
    }
    public AbstractShip getShip(){
        return ship;
    }
    public boolean isSunk(){
        return ship.strikeCount==ship.getLength();
    }
    public boolean isStruck(){
        return struck;
    }
    /**
     Adds a strike to the ship.
     It is used in order to track if the ship has sunk or not.
     */
    public void addStrike(){
        if(!struck) {
            struck = true;
            if (isShip()) {
                ship.strikeCount++;
            }
        }
    }
    public String toString(){
        if (ship!=null) {
            return ship.getLabel().toString();
        }else {
            return ".";
        }
    }
    /**
     This is useful to populate the table representing the ships without having to convert a String to char each time
     */
    public char getShipAsChar(){
        if (ship==null) {
            return '.';
        }else {
            return ship.getShipType().getAsChar();
        }
    }

}
<file_sep>package com.excilys.formation.battleships.android.ui;

import android.app.Application;
import android.content.Intent;

import com.excilys.formation.battleships.AIPlayer;
import com.excilys.formation.battleships.Board;
import com.excilys.formation.battleships.Player;
import com.excilys.formation.battleships.android.ui.ships.DrawableBattleship;
import com.excilys.formation.battleships.android.ui.ships.DrawableCarrier;
import com.excilys.formation.battleships.android.ui.ships.DrawableDestroyer;
import com.excilys.formation.battleships.android.ui.ships.DrawableSubmarine;
import com.excilys.formation.battleships.ship.AbstractShip;

import java.util.Arrays;
import java.util.List;

public class BattleShipsApplication extends Application {

    /* ***
     * Attributes
     */
    // BoardController = Implements the visual part of the Board on top of the Board logic
    private static BoardController mBoardcontroller;
    // The opponent Board, at first it will just be an AI, but could be another player over network
    private static Board mOpponentBoard;
    // The game object itself created during the start of the application by the
    // onCreate method
    private static Game mGame;
    // Stores the player's name
    private String mPlayerName;
    // Stores the the players
    private static Player[] mPlayers;

    public BoardController getBoardController(){
        return mBoardcontroller;
    }

    static public Board getOpponentBoard(){
        return mOpponentBoard;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mGame = new Game();
    }

    public static Game getGame() {
        return mGame;
    }

    public static BoardController getBoard() {
        return mBoardcontroller;
    }

    public static Player[] getPlayers() {
        return mPlayers;
    }

    /* ***
     * Nested classes
     */
    public class Game {
        /* ***
         * Attributes
         */
        private AndroidPlayer mPlayer1;
        private Player mPlayer2;
        /* ***
         * Methods
         */
        public Game init(String playerName) {
            mPlayerName = playerName;
            Board board = new Board(playerName);
            mBoardcontroller = new BoardController(board);
            mOpponentBoard = new Board("IA");
            // Android Player is the "regular player", but the putShips opens an Android Activity
            // so the ships can be put using a nice interface
            mPlayer1 = new AndroidPlayer(playerName, board, mOpponentBoard, createDefaultShips());
            mPlayer2 = new AIPlayer(mOpponentBoard, board, createDefaultShips());
            mPlayers = new Player[] {mPlayer1, mPlayer2};
            // Show the putShips view and wait for the player to put it's ships.
            mPlayer1.putShips();
            return this;
        }

        private List<AbstractShip> createDefaultShips() {
            AbstractShip[] ships;
             ships = new AbstractShip[]{new DrawableDestroyer(), new DrawableSubmarine(), new DrawableSubmarine(), new DrawableBattleship(), new DrawableCarrier()};
            return Arrays.asList(ships);
        }
    }

    public class AndroidPlayer extends Player {
        // Just a regular "Player" class apart from the putShips method which is overloaded
        AndroidPlayer(String name, Board board, Board opponentBoard, List<AbstractShip> ships){
            super(name, board, opponentBoard, ships);
        }
        void putShips() {
            Intent intent = new Intent(getApplicationContext(), PutShipsActivity.class);
            startActivity(intent);
        }

    }

}
