Вопрос

I am currently working on a minesweeper program and i need a little help on revealing neighbors in it. Currently what my program can do for reveals is the following

The 1 would be the button that was selected and the lines are what i need to be filled in. Currently the buttons of around the button selected are what i can get to fill in.

I can post code if necessary.

Thanks for the help in advance. enter image description here

1 is a mine, 4 is a flagged spot on the array

public int findneighbors(int row, int col) {
      int count = 0;
    if (board[row][col] == 2)
        try {
            if (board[row][col + 1] == 1 || board[row][col + 1] == 4)
                count ++;
        }

            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
        if (board[row + 1][col + 1] == 1 || board[row + 1][col + 1] == 4)
            count ++;
            }
        catch( ArrayIndexOutOfBoundsException e)
        {
        }
        try {
        if (board[row + 1][col - 1] == 1 || board[row + 1][col - 1] == 4)
            count ++;
            }
        catch( ArrayIndexOutOfBoundsException e)
        {
        }
        try {
            if (board[row - 1][col - 1] == 1 || board[row - 1][col - 1] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
            if (board[row][col + 1] == 1 || board[row][col + 1] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
            if (board[row + 1][col] == 1 || board[row + 1][col] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
            if (board[row - 1][col] == 1 || board[row - 1][col] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
            if (board[row][col - 1] == 1 || board[row][col - 1] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }
        try {
            if (board[row - 1][col + 1] == 1 || board[row - 1][col + 1] == 4)
                count ++;
                }
            catch( ArrayIndexOutOfBoundsException e)
            {
            }

    return count;
  }
public int buttonFloodFill(int r, int c)
{
    int loopCount = 0;
    int rowCount = 1;
    int colCount = 1;
    while (loopCount < 1)
    {
        try {
    if (g.getFloodValue(r,c + colCount) == true) {
        board[r][c + colCount].setText(Integer.toString(g.findneighbors(r,c + colCount)));
        board[r][c + colCount].setEnabled(false);
    }
        }
    catch( ArrayIndexOutOfBoundsException e)
    {
    }
    try {
    if (g.getFloodValue(r,c - colCount) == true) {
        board[r][c - colCount].setText(Integer.toString(g.findneighbors(r,c - colCount)));
        board[r][c - colCount].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r + rowCount,c + colCount) == true) {
        board[r + rowCount][c + colCount].setText(Integer.toString(g.findneighbors(r + rowCount,c + colCount)));
        board[r + rowCount][c + colCount].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r + rowCount,c - colCount) == true) {
        board[r + rowCount][c - colCount].setText(Integer.toString(g.findneighbors(r + rowCount,c - colCount)));
        board[r + rowCount][c - colCount].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r - rowCount,c - colCount) == true) {
        board[r - rowCount][c - colCount].setText(Integer.toString(g.findneighbors(r - rowCount,c - colCount)));
        board[r - rowCount][c - colCount].setEnabled(false);
        }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r - rowCount,c + colCount) == true) {
        board[r - rowCount][c + colCount].setText(Integer.toString(g.findneighbors(r - rowCount,c + colCount)));
        board[r - rowCount][c + colCount].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r - rowCount,c) == true) {
        board[r - rowCount][c].setText(Integer.toString(g.findneighbors(r - rowCount,c)));
        board[r - rowCount][c].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    try {
    if (g.getFloodValue(r + rowCount,c) == true) {
        board[r + rowCount][c].setText(Integer.toString(g.findneighbors(r+ rowCount,c)));
        board[r + rowCount][c].setEnabled(false);
    }
    }
catch( ArrayIndexOutOfBoundsException e)
{
}
    rowCount ++;
    colCount ++;
    loopCount ++;

    }
    return 0;
}
Это было полезно?

Решение

While I haven't read your code, it looks like you need to learn some more basic techniques such as loops and refactoring using small helper functions. I can see that you're not interested in exception handling, which is fine for now for a program of this scale, but there are more visually-pleasing (and readability-increasing) solutions, such as merging the consecutive try-catch blocks into one or simply declaring the function to possibly throw.

As for your question, recursion is the answer. You cannot keep checking neighbors and neighbors-of-neighbors and their neighbors and so on. You need to come up with a repeating pattern. Flood fill is the actual answer, but you need to familiarize yourself with recursion and learn to identify problems it might solve.

Другие советы

Alright, after seeing your code i think it's best to give you some general guidelines rather than trying to fix this specific problem.

Java is a language designed for object-oriented programming. What you did is more of a procedural approach, which also works of course, but since you are working with Java, I assume you want to use the language features to your advantage.

Let's see what kind of 'objects' we can find in your project. You already have a board, the array of the cells. The code you showed would be part of this board, which you can seperate from the code that has nothing to do with the board.

Currently, your board consists of integers representing the state of that cell. Now, wouldn't it be interesting to make cell an object as well? That way, a board would have an array of cells, which have a state. Now you could say this just increases the number of levels you have to reason about. In a way this is also true, however, each of these levels is a clearly defined concept which you can reason about individually. Let's look at some example code:

class Cell {
    private int state; //whatever your default is

    public Cell(int state) {
        this.state = state;
    }

Now we can add some methods to inspect the state:

    public boolean hasMine() {
         return state == 1;
    }
    public boolean isFlagged() {
         return state == 4;
    }

Similarly, you can add methods to change the state:

    public void flag() {
        state = 4;
    }

I've only listed a few methods, I think it should be clear how to write the further ones. (Also, I've kept the state as an integer for now. Once you're more advanced in OO-programming you may want to look at Java Enumerations or the State pattern)

Now let's look at the board. You currently have a method called findneighbours, which returns the number of adjecent mines. Personally, I would call this method something more clear, like getAdjecentMineCount. However, I would expect a getNeighbours method to exist as well, which returns the all the adjecent cells of a cell. You can then use this getNeighbours method to easily find the number of adjecent mines, like this:

public int getAdjecentMineCount(int row, int col) {
    int count=0;
    for (Cell c : getNeighbours(row, col)) //this iterates over the neighbours that are returned by the getNeighbours function
        if (c.hasMine())
             count++;
    return count;
}

Now, let's look at revealing a cell. Let's not make it hard and make a method called revealCell:

public void revealCell(int row, int col) {
    if (board[row][col].hasMine())
        System.out.println("BOOM"); //whatever has to happen when you click on a bomb
    //now we also want to reveil any non-diagonal neighbour that doesn't have a mine
    for (Cell c : getNonDiagonalNeighbours(row, col))
        if (!c.hasMine() && !c.isRevealed())
             reveilCell(rowOf(c), columnOf(c));
}

Notice the recursive call to the same method again. This will cause the chain of cells to be reveiled.

I've purposefully left some holes in my code, such as the methods to find the neighbours. I hope that my explanation will push you in the right way, and that you can figure out more about the language by yourself. Feel free to contact me if you have further problems.

(Disclaimer: by no means do I claim that the solution I'm feeding to you here is the ideal solution. All I'm aiming to do is guide you to write cleaner and more object oriented code.)

Forgive me for reimplementing your entire code but that's faster than trying to understand yours ...

public class Minefield {

    int mx, my;

    /** whether a mine is present */
    boolean[][] mined;

    /** the number of mines in neighboring cells */
    int[][] mines;

    /** whether this cell is revealed */
    boolean[][] revealed;

    public Minefield() {
        Random chaos = new Random();

        mx = 10;
        my = 10;
        for (int x = 0; x < mx; x++) {
            for (int y = 0; y < my; y++) {
                mined[x][y] = chaos.nextFloat() < 0.2;
            }
        }

        for (int x = 0; x < mx; x++) {
            for (int y = 0; y < my; y++) {
                mines[x][y] = 0;
                for (int nx = max(x - 1, 0); nx < mx && nx <= x + 1; nx++) {
                    for (int ny = max(y - 1, 0); ny < my && ny <= y + 1; ny++) {
                        if (mined[nx][ny]) {
                            mines[x][y]++;
                        }
                    }
                }
            }
        }
    }

    void stepOn(int x, int y) {
        reveal(x, y);
        if (mined[x][y]) {
            throw new GameOverException();
        }
    }

    void reveal(int x, int y) {
        if (!revealed[x][y]) {
            revealed[x][y] = true;
            if (mines[x][y] == 0) {
                for (int nx = max(x - 1, 0); nx < mx && nx <= x + 1; nx++) {
                    for (int ny = max(y - 1, 0); ny < my && ny <= y + 1; ny++) {
                        reveal(nx, ny);
                    }
                }
            }
        }
    }

Note: I haven't tested that code, but I hope you'll get the idea.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top