Previous review can be found here
I got so many great tips on how to improve, so I've written a new version while trying to implement all the different suggestions.
So once again, any insight with regards to clean code, best practices etc. would be greatly appreciated.
Board.java
package com.tn.board;
import com.tn.field.IGameField;
import com.tn.field.WaterField;
import com.tn.ship.Ship;
import com.tn.field.ShipField;
import com.tn.ship.ShipSize;
import java.awt.*;
import java.util.Scanner;
public class Board {
    private static final char WATER = '~';
    private static final int BOARD_SIZE = 10;
    private static final char[] BOARD_LETTERS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    private static final String HORIZONTAL = "H";
    private static final String VERTICAL = "V";
    private Scanner scanner;
    private IGameField[][] board;
    private static final Ship[] ships;
    static {
        ships = new Ship[] {
                new Ship("Carrier", ShipSize.CARRIER),
                new Ship("Battleship", ShipSize.BATTLESHIP),
                new Ship("Cruiser", ShipSize.CRUISER),
                new Ship("Submarine", ShipSize.SUBMARINE),
                new Ship("Destroyer", ShipSize.DESTROYER)
        };
    }
    public Board() {
        this.scanner = new Scanner(System.in);
        this.board = new IGameField[BOARD_SIZE][BOARD_SIZE];
        for(int i = 0; i < BOARD_SIZE; i++) {
            for(int j = 0; j < BOARD_SIZE; j++) {
                board[i][j] = new WaterField();
            }
        }
    }
    public void placeShipsOnBoard() {
        for(Ship ship : ships) {
            boolean horizontal = askValidShipDirection();
            Point startingPoint = askValidStartingPoint(ship, horizontal);
            placeValidShip(ship, startingPoint, horizontal);
            printBoard();
        }
    }
    public IGameField getField(int x, int y) {
        if(!isInsideBoard(x, y)) {
            throw new IllegalArgumentException("Outside board - try again: ");
        }
        return board[y][x];
    }
    public void printBoard() {
        System.out.print("\t");
        for(int i = 0; i < BOARD_SIZE; i++) {
            System.out.print(BOARD_LETTERS[i] + "\t");
        }
        System.out.println();
        for(int i = 0; i < BOARD_SIZE; i++) {
            System.out.print((i+1) + "\t");
            for(int j = 0; j < BOARD_SIZE; j++) {
                System.out.print(board[i][j].getIcon() + "\t");
            }
            System.out.println();
        }
    }
    private boolean askValidShipDirection() {
        System.out.printf("%nDo you want to place the ship horizontally (H) or vertically (V)?");
        String direction;
        do {
            direction = scanner.nextLine().trim();
        }while (!HORIZONTAL.equals(direction) && !VERTICAL.equals(direction));
        return HORIZONTAL.equals(direction);
    }
    private Point askValidStartingPoint(Ship ship, boolean horizontal) {
        Point from;
        do {
            System.out.printf("%nEnter position of %s (length  %d): ", ship.getName(), ship.getSize());
            from = new Point(scanner.nextInt(), scanner.nextInt());
        } while(!isValidStartingPoint(from, ship.getSize(), horizontal));
        return from;
    }
    private boolean isValidStartingPoint(Point from, int length, boolean horizontal) {
        int xDiff = 0;
        int yDiff = 0;
        if(horizontal) {
            xDiff = 1;
        } else {
            yDiff = 1;
        }
        int x = (int)from.getX() - 1;
        int y = (int)from.getY() - 1;
        if(!isInsideBoard(x, y) ||
                (!isInsideBoard(x + length,y) && horizontal) ||
                (!isInsideBoard(x, y + length) && !horizontal)
                ) {
            return false;
        }
        for(int i = 0; i < length; i++) {
            if(board[(int)from.getY() + i *yDiff - 1]
                    [(int)from.getX() + i *xDiff - 1].getIcon() != WATER){
                return false;
            }
        }
        return true;
    }
    private void placeValidShip(Ship ship, Point startingPoint, boolean horizontal) {
        int xDiff = 0;
        int yDiff = 0;
        if(horizontal) {
            xDiff = 1;
        } else {
            yDiff = 1;
        }
        for(int i = 0; i < ship.getSize() ; i++) {
            board[(int)startingPoint.getY() + i*yDiff - 1]
                    [(int)startingPoint.getX()+ i*xDiff - 1] = new ShipField(ship);
        }
    }
    private boolean isInsideBoard(int x, int y){
        return x <= BOARD_SIZE && x >= 0
                && y <= BOARD_SIZE && y >= 0;
    }
}
IGameField.java
package com.tn.field;
import com.tn.game.Result;
public interface IGameField {
    char getIcon();
    Result shootAt();
}
ShipField.java
package com.tn.field;
import com.tn.game.Result;
import com.tn.ship.Ship;
public class ShipField implements IGameField {
    private final Ship ship;
    public ShipField(Ship ship) {
        this.ship = ship;
    }
    @Override
    public char getIcon() {
        char icon;
        Result shipState = ship.getState();
        switch (shipState) {
            case PARTIAL_HIT: icon = 'O';
                break;
            case DESTROYED: icon = 'O';
                break;
            case NO_HIT: icon = 'X';
                break;
            default: icon = ' ';
                break;
        }
        return icon;
    }
    @Override
    public Result shootAt() {
        ship.hit();
        return ship.getState();
    }
}
WaterField.java
package com.tn.field;
import com.tn.game.Result;
public class WaterField implements IGameField {
    private boolean isThisFieldHit = false;
    @Override
    public char getIcon() {
        return isThisFieldHit ? 'M' : '~';
    }
    @Override
    public Result shootAt() {
        isThisFieldHit = true;
        return Result.NO_HIT;
    }
}
IPlayer.java
package com.tn.player;
public interface IPlayer {
    void placeShips();
    void fireAt(IPlayer opponent);
    int getTotalLivesLeft();
}
HumanPlayer.java
package com.tn.player;
import com.tn.board.Board;
import com.tn.game.Result;
import java.awt.*;
import java.util.Scanner;
public class HumanPlayer implements IPlayer {
    private int totalLivesLeft = 17;
    private int id;
    private Board board;
    private Scanner scanner;
    public HumanPlayer(int id) {
        this.id = id;
        this.board = new Board();
        this.scanner = new Scanner(System.in);
    }
    public int getId() {
        return id;
    }
    public Board getBoard() {
        return board;
    }
    @Override
    public void placeShips() {
        System.out.printf("%n======== Player %d - Time to place out your ships ========%n", id);
        board.placeShipsOnBoard();
    }
    @Override
    public void fireAt(IPlayer opponent) {
        System.out.printf("%n Alright Player %d - Enter coordinates for your attack: ", id);
        boolean isPointValid = false;
        while(!isPointValid) {
            try {
                Point point = new Point(scanner.nextInt(), scanner.nextInt());
                int x = (int)point.getX() - 1;
                int y = (int)point.getY() - 1;
                Result result = ((HumanPlayer)opponent)
                        .getBoard()
                        .getField(x, y)
                        .shootAt();
                if(result == Result.PARTIAL_HIT ||  result == Result.DESTROYED) {
                    totalLivesLeft--;
                }
                isPointValid = true;
            } catch(IllegalArgumentException e) {
                System.out.printf(e.getMessage());
            }
        }
    }
    @Override
    public int getTotalLivesLeft() {
        return totalLivesLeft;
    }
}
Ship.java
package com.tn.ship;
import com.tn.game.Result;
public class Ship {
    private final String name;
    private final int size;
    private int lives;
    public Ship(String name, int size) {
        this.name = name;
        this.size = size;
        this.lives = size;
    }
    public void hit() {
        if(lives > 0) {
            System.out.printf("%nGood shot! The %s was hit", name);
            lives--;
        } else {
            System.out.println("Ship is destroyed");
        }
    }
    public Result getState() {
        if(lives == 0) {
            return Result.DESTROYED;
        } else if(lives < size) {
            return Result.PARTIAL_HIT;
        } else {
            return Result.NO_HIT;
        }
    }
    public String getName() {
        return name;
    }
    public int getSize() {
        return size;
    }
}
ShipSize.java
package com.tn.ship;
public class ShipSize {
    private ShipSize() {
    }
    public static final int CARRIER = 5;
    public static final int BATTLESHIP = 4;
    public static final int CRUISER = 3;
    public static final int SUBMARINE = 3;
    public static final int DESTROYER = 2;
}
Result.java
package com.tn.game;
public enum Result {
    NO_HIT,
    PARTIAL_HIT,
    DESTROYED
}
Game.java
package com.tn.game;
import com.tn.player.HumanPlayer;
public class Game {
    private HumanPlayer[] players;
    public Game() {
        this.players = new HumanPlayer[]{
                new HumanPlayer(1),
                new HumanPlayer(2)
        };
    }
    public void start() {
        int i = 0;
        int j = 1;
        int len = players.length;
        HumanPlayer player = null;
        this.players[i].placeShips();
        this.players[j].placeShips();
        while(players[0].getTotalLivesLeft() > 0 &&
                players[1].getTotalLivesLeft() > 0) {
            players[i++ % len].fireAt(players[j++ % len]);
            player = (players[0].getTotalLivesLeft() < players[1].getTotalLivesLeft()) ?
                    players[1] :
                    players[0];
        }
        System.out.printf("Congrats Player %d, you won!",player.getId());
    }
}
Main.java
import com.tn.game.Game;
public class Main {
    public static void main(String[] args) {
        Game game = new Game();
        game.start();
    }
}