Search code examples
javaalgorithmprobabilitybigdecimal

Facebook warm up challenge that I can't seem to figure out - Battleship


I am working on this MetaCareers code challenge (needs an account):

You're playing Battleship on a grid of cells with 𝑅 rows and 𝐶 columns. There are 0 or more battleships on the grid, each occupying a single distinct cell. The cell in the 𝑖th row from the top and 𝑗th column from the left either contains a battleship (𝐺𝑖,𝑗​=1) or doesn't (𝐺𝑖,𝑗​=0).

You're going to fire a single shot at a random cell in the grid. You'll choose this cell uniformly at random from the 𝑅∗𝐶 possible cells. You're interested in the probability that the cell hit by your shot contains a battleship.

Your task is to implement the function getHitProbability(R, C, G) which returns this probability.

Note: Your return value must have an absolute or relative error of at most 10─6 to be considered correct.

Constraints

  • 1 ≤ 𝑅,𝐶 ≤ 100
  • 0 ≤ 𝐺𝑖,𝑗​ ≤ 1

Sample test case #1

R = 2
C = 3
G = 0 0 1
    1 0 1
Expected Return Value = 0.50000000

Sample test case #2

R = 2
C = 2
G = 1 1
    1 1
Expected Return Value = 1.00000000

Sample Explanation

In the first case, 3 of the 6 cells in the grid contain battleships. Therefore, the probability that your shot will hit one of them is 3 / 6 = 0.5.

In the second case, all 4 cells contain battleships, resulting in a probability of 1.0 of hitting a battleship.

So it seems clear that the probability = ships / grid_size

And I'm rounding it to the 8th decimal -- which I can't seem to get right.... What is my mistake?

My code attempt:

if (G.length == 0) return 0;
double ships = 0.00000000;
for (int[] i : G) {
    if (i[0] == 1) ships++;
}
float ans = Math.round((ships / (float) G.length) * 100000000) / 100000000.0f;
System.out.println(String.valueOf(ans));
String ans = String.format("%.8f", (ships / G.length));
// System.out.println(ans);
// BigDecimal bd1 = new BigDecimal(ships/G.length);
// System.out.println(bd1);

Solution

  • These are the issues in your code attempt:

    • It only looks at the first column of the given grid -- with i[0] -- not considering that there might be ships at i[1], i[2], ...etc.
    • It miscalculates the total number of cells in the grid, as G.length represents the number of rows, not taking into account the number of columns. The total number of cells is G.length * G[0].length.
    • It attempts to redefine the variable ans which will not allow the code to compile.
    • It does not execute a return after having defined ans.
    • It converts a calculated value to String, while the return type of the function is double.

    Not a real problem, but:

    • It attempts to round a value to 8 decimal digits, but this is not necessary, as that will only make the answer less accurate.
    • It deals with the case where the grid is empty, but this case will never happen, as 𝑅 and 𝐶 are guaranteed to be at least 1.
    • Instead of testing the value of the cell, you could just add the cell's value to the ships value, given that the cell's value is guaranteed to be 0 or 1 and adding 0 leaves the value of ships unchanged.

    Here is the correction of your code as a spoiler:

    public double getHitProbability(int R, int C, int[][] G) { double ships = 0; for (int[] row : G) { for (int val : row) { // Visit each cell in the row ships += val; // Add the cell's value unconditionally } } return ships / (G.length * G[0].length); // The total number of cells is R*C }