1

I am following a course by princeton university on cousera, I wrote the following code for the following problem:

Minesweeper. Minesweeper is a 1960s era video game played on an m-by-n grid of cells. The goal is to deduce which cells contain hidden mines using clues about the number of mines in neighboring cells. Write a program Minesweeper.java that takes three integer command-line arguments m, n, and k and prints an m-by-n grid of cells with k mines, using asterisks for mines and integers for the neighboring mine counts (with two space characters between each cell). To do so, Generate an m-by-n grid of cells, with exactly k of the mn cells containing mines, uniformly at random. For each cell not containing a mine, count the number of neighboring mines (above, below, left, right, or diagonal).

Every time I submit to the grader; it says the 60 second limit was exceeded, and it stops grading.

This is the desired output

enter image description here

public class Minesweeper {

    public static void main(String[] args) {

        int m = Integer.parseInt(args[0]);
        int n = Integer.parseInt(args[1]);
        int k = Integer.parseInt(args[2]);

        boolean[][] minePositions = new boolean[m + 2][n + 2];
        int[][] grid = new int[m + 2][n + 2];

        int num = 0;
        while (num != k) {
            if ((m * n) == k) {
                for (int f = 1; f <= m; f++) {
                    for (int z = 1; z <= n; z++) {
                        minePositions[f][z] = true;
                    }
                }
                break;
            }
            int r = (int) (Math.random() * (m * n - 1));
            int q = r / n;
            int rem = r % n;
            if (q == 0) {
                q = 1;
            }
            else if (q > (m - 1)) {
                q = m - 1;
            }
            if (rem == 0) {
                rem = 1;
            }
            else if (rem > (n - 1)) {
                rem = n - 1;
            }
            
            if (!minePositions[q][rem]) {
                minePositions[q][rem] = true;
                num++;
            }
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (minePositions[i - 1][j + 1]) grid[i][j]++;
                if (minePositions[i][j + 1]) grid[i][j]++;
                if (minePositions[i + 1][j + 1]) grid[i][j]++;
                if (minePositions[i - 1][j]) grid[i][j]++;
                if (minePositions[i + 1][j]) grid[i][j]++;
                if (minePositions[i - 1][j - 1]) grid[i][j]++;
                if (minePositions[i][j - 1]) grid[i][j]++;
                if (minePositions[i + 1][j - 1]) grid[i][j]++;
            }
            for (int j = 1; j <= n; j++) {
                if (minePositions[i][j]) System.out.print("*  ");
                else System.out.print(grid[i][j] + "  ");
            }
            System.out.print("\n");
        }

    }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
  • You are likely timing out on a test that generates a very "dense" minefield because you are using acceptance/rejection testing for the placement of a mine, which if the field is very dense, you could be in that loop for a loooooong time. Is there a way to randomly distribute the mines without having to test the placement to see if there is already one there? (hint: yes) – AirSquid Oct 29 '21 at 16:09

1 Answers1

1

I think using arrays of size (m + 2, n + 2) confused your math here. I'll continue on your work, always use m + 2 and n + 2 in your calculations to avoid any confusion.

int r = (int) (Math.random() * ((m + 2) * (n + 2)));

Generate a random number than can span all your array cells.

int q = r / (n + 2);
int rem = r % (n + 2);

// Increment num only if q and rem are in the ranges and the position does not have a mine on it
if (q > 0 && q <= m && rem > 0 && rem <= n && !minePositions[q][rem]) {
    minePositions[q][rem] = true;
    num++;
}

The full code

int m = Integer.parseInt(args[0]);
int n = Integer.parseInt(args[1]);
int k = Integer.parseInt(args[2]);

boolean[][] minePositions = new boolean[m + 2][n + 2];
int[][] grid = new int[m + 2][n + 2];

int num = 0;
while (num != k) {
    int r = (int) (Math.random() * ((m + 2) * (n + 2)));
    int q = r / (n + 2);
    int rem = r % (n + 2);

    if (q > 0 && q <= m && rem > 0 && rem <= n && !minePositions[q][rem]) {
        minePositions[q][rem] = true;
        num++;
    }
}

for (int i = 1; i <= m; i++) {
    for (int j = 1; j <= n; j++) {
        if (minePositions[i - 1][j + 1]) grid[i][j]++;
        if (minePositions[i][j + 1]) grid[i][j]++;
        if (minePositions[i + 1][j + 1]) grid[i][j]++;
        if (minePositions[i - 1][j]) grid[i][j]++;
        if (minePositions[i + 1][j]) grid[i][j]++;
        if (minePositions[i - 1][j - 1]) grid[i][j]++;
        if (minePositions[i][j - 1]) grid[i][j]++;
        if (minePositions[i + 1][j - 1]) grid[i][j]++;
    }
    for (int j = 1; j <= n; j++) {
        if (minePositions[i][j]) System.out.print("*  ");
        else System.out.print(grid[i][j] + "  ");
    }
    System.out.print("\n");
}
b.GHILAS
  • 2,273
  • 1
  • 8
  • 16
  • Alright, I like your calculation of generating random number, would you carter to explain it. Plus you should consider the case, where the number of mines are a product of the row and column e.g 8 4 32, that is the reason why of the two nested for loops in the while loops – Alinaswe klb Oct 29 '21 at 15:04
  • @Alinasweklb you don't need the nested loops, if the number of mines equals m * n, it'll be generated correctly no matter how many times the loop executes, it'll generate all the numbers between 0 to (n+2)(m+2) - 1 – b.GHILAS Oct 29 '21 at 15:18
  • I tried it without the nested loops but the program went on running for a long time. – Alinaswe klb Oct 29 '21 at 15:34
  • @Alinasweklb what are the values of m, n and k you used ? – b.GHILAS Oct 29 '21 at 15:35
  • the same 8 4 32 that I told you about – Alinaswe klb Oct 29 '21 at 15:39
  • @Alinasweklb sorry made a mistake, I updated the solution, we have to divide by n + 2 and not m + 2 – b.GHILAS Oct 29 '21 at 15:39
  • any two factors could do like 12 12 144 or 2 2 4 – Alinaswe klb Oct 29 '21 at 15:40
  • Ohh I see it but how does that fix the problem – Alinaswe klb Oct 29 '21 at 15:40
  • to calculate the row of the random number we must divide by the number of columns but I divided by the number of rows which is wrong, and the same for the column of the random number – b.GHILAS Oct 29 '21 at 15:42
  • @Alinasweklb if this answer your problem mark it as the accepted response – b.GHILAS Oct 29 '21 at 16:01
  • this solution places mines outside the m x n grid... and is inefficient in mine placement. – AirSquid Oct 29 '21 at 16:17
  • @AirSquid yes you're right, this is why I said in the response "I'll continue on your work". Feel free to edit the answer to include a better approach or add a new response – b.GHILAS Oct 29 '21 at 16:21