I am fairly new to Java and I have been working on a Minesweeper game. I am trying to get the adjacent cells to be revealed recursively when an empty cell is clicked. I do this by calling showCell() shown below:
Cells array declaration and population:
private final Cell[][] cells;
public void newGame()
{
numMinesLeft = NUM_MINES;
numCellsLeft = NUM_ROWS * NUM_COLS;
hasHitMine = false;
Cell[] newCells = new Cell[NUM_ROWS * NUM_COLS];
int k = 0; // index in newCells
// create the cells with the mines
while (k < NUM_MINES && k < newCells.length)
{
newCells[k] = new Cell(MINE);
k++;
}
// create the cells without the mines
while (k < newCells.length)
{
newCells[k] = new Cell();
k++;
}
// uniformly mix newCells
for (k = newCells.length; k > 1;)
{
int r = generator.nextInt(k);
k--;
// interchange newCells[r] and newCells[k]
Cell temp = newCells[k];
newCells[k] = newCells[r];
newCells[r] = temp;
}
k = 0;
// place cells into the cells array
for (int i = 0; i < NUM_ROWS; ++i)
{
for (int j = 0; j < NUM_COLS; ++j)
{
cells[i][j] = newCells[k];
k++;
}
}
for(int i = 0; i<NUM_ROWS; i++)
{
for (int j = 0; j<NUM_COLS; j++)
{
int numOfBorderMines = 0;
if (cells[i][j].value != MINE)
{
if(isInTheGrid(i-1, j) == true)
{
if (cells[i-1][j].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i+1, j) == true)
{
if (cells[i+1][j].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i, j - 1) == true)
{
if (cells[i][j - 1].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i, j + 1) == true)
{
if (cells[i][j + 1].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i - 1, j + 1) == true)
{
if (cells[i - 1][j + 1].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i + 1, j - 1) == true)
{
if (cells[i + 1][j - 1].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i + 1, j + 1) == true)
{
if (cells[i + 1][j + 1].value == MINE )
{
numOfBorderMines++;
}
}
if(isInTheGrid(i - 1, j - 1) == true)
{
if (cells[i - 1][j - 1].value == MINE )
{
numOfBorderMines++;
}
}
cells[i][j].value = numOfBorderMines;
}
}
}
}
toggleFlag()
public void toggleFlag(int row, int col)
{
if (isCellShowing(row, col) || isOver()) return;
if (isCellFlagged(row, col))
{
// unflag cell
cells[row][col].hasFlag = false;
numMinesLeft++;
numCellsLeft++;
}
else if (numMinesLeft > 0)
{
// flag cell
cells[row][col].hasFlag = true;
numMinesLeft--;
numCellsLeft--;
}
ui.updateCell(row, col);
}
showCell()
public void showCell(int row, int col)
{
// checks is cell has been flagged or if the game is over, otherwise it reveals the cell
if(isCellFlagged(row, col) == true || isOver())
{
return;
}
else
{
cells[row][col].isShowing = true;
ui.updateCell(row, col);
}
// checks if cell has a mine and triggers hasHitMine otherwise subtracts 1 from class variable numCellsLeft
if (cells[row][col].value == MINE)
{
hasHitMine = true;
}
else
{
numCellsLeft--;
}
// if there are no mines adjacent, recursively reveal the adjacent cells
if(cells[row][col].value == 0)
{
showCell(row + 1, col);
showCell(row - 1, col);
showCell(row, col + 1);
showCell(row, col -1);
showCell(row + 1, col - 1);
showCell(row + 1, col + 1);
showCell(row - 1, col - 1);
showCell(row - 1, col + 1);
}
}
The problem I am having is when I hit this portion of the code and click an empty cell, it reveals all cells adjacent continuously down a column or a row in one direction. I can't get my implementation of recursion right, perhaps I am approaching it wrong. My idea was to reveal each adjacent cell according to the grid position.
I solved my problem by implementing Tail Recursion. Here is my updated showCell() method and tail recursion method:
public void showCell(int row, int col)
{
// checks is cell has been flagged or if the game is over, otherwise it reveals the cell
if(isCellFlagged(row, col) == true || isOver())
{
return;
}
else
{
cells[row][col].isShowing = true;
ui.updateCell(row, col);
}
// checks if cell has a mine and triggers hasHitMine otherwise subtracts 1 from class variable numCellsLeft
if (cells[row][col].value == MINE)
{
hasHitMine = true;
}
else
{
numCellsLeft--;
}
// if there are no mines adjacent, recursively reveal the adjacent cells
if(cells[row][col].value == 0)
{
if(isInTheGrid(row - 1, col) == true)
{
showCell(row - 1, col, cells[row - 1][col].isShowing);
}
if(isInTheGrid(row + 1, col) == true)
{
showCell(row + 1, col, cells[row + 1][col].isShowing);
}
if(isInTheGrid(row, col - 1) == true)
{
showCell(row, col - 1, cells[row][col - 1].isShowing);
}
if(isInTheGrid(row, col + 1) == true)
{
showCell(row, col + 1, cells[row][col + 1].isShowing);
}
if(isInTheGrid(row + 1, col - 1) == true)
{
showCell(row + 1, col - 1, cells[row + 1][col - 1].isShowing);
}
if(isInTheGrid(row - 1, col + 1) == true)
{
showCell(row - 1, col + 1, cells[row - 1][col + 1].isShowing);
}
if(isInTheGrid(row + 1, col + 1) == true)
{
showCell(row + 1, col + 1, cells[row + 1][col + 1].isShowing);
}
if(isInTheGrid(row - 1, col - 1) == true)
{
showCell(row - 1, col - 1, cells[row - 1][col - 1].isShowing);
}
}
else
{
return;
}
}
public boolean isInTheGrid(int x, int y)
{
if (x < 0 || y < 0) return false;
if(x >= NUM_ROWS || y >= NUM_COLS) return false;
return true;
}
public void showCell(int row, int col, boolean isShown)
{
if (isShown != true)
{
cells[row][col].isShowing = true;
ui.updateCell(row, col);
}
else
{
return;
}
}
When you call show cell for surrounding cells, you want to make sure that you don't re-show the cell you called it from, or past cells that were shown from the previous calls in the recursion stack.
If I understood your question correctly, I believe you are referring the case in Minesweeper where if you click on an empty cell, then it will reveal the adjacent empty cells.
Currently working on a class project trying to recreate Conway's Game of Life. Here's a copy of my code, my main issue is with my runRound() method. I have to go through and check to see how many neighbors each cell has that are alive(true) or dead(false) and edit my new grid accordingly. However I keep going out of bounds when trying to check around the edges of my grid and tried to implement code to avoid that but I must be missing something. Thank for any advice! still kind of new to this!
package Programs;
public class GameOfLife {
private boolean[][] grid;
private int time;
public GameOfLife() {
grid = new boolean[10][10];
time = 0;
}
public GameOfLife(int row, int col) {
if (row < 1) {
row = 10;
}
if (col < 1) {
col = 10;
}
grid = new boolean[row][col];
time = 0;
}
public boolean[][] getGrid() {
boolean[][] newGrid = new boolean[grid.length][grid[1].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
newGrid[i][j] = grid[i][j];
}
}
return newGrid;
}
public int getTime() {
return time;
}
public void simpleSetUp(int[][] array) {
if (getTime() == 0) {
for (int row = 0; row < array.length; row++) {
if (array[0].length == 2) {
if (array[row][0] >= 0 && array[row][1] >= 0 && array[row][0] <= grid[0].length
&& array[row][1] <= grid[0].length) {
grid[array[row][0]][array[row][1]] = true;
}
}
}
}
}
public void clearGrid() {
this.time = 0;
for (int row = 0; row < grid.length; row++) {
for (int col = 0; row < grid[col].length; col++) {
grid[row][col] = false;
}
}
}
public void runRound() {
time++;
int live;
boolean[][] newGrid = getGrid();
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[col].length; col++) {
live = 0;
if (row - 1 >= 0 || col - 1 >= 0) {
if(grid[row - 1][col - 1] == true){
live++;
}
}
if (row + 1 < grid.length || col + 1 < grid[col].length) {
if(grid[row + 1][col + 1] == true){
live++;
}
}
if (row - 1 >= 0 || col + 1 < grid[col].length) {
if(grid[row - 1][col + 1] == true ){
live++;
}
}
if (row + 1 < grid.length || col - 1 >= 0) {
if(grid[row + 1][col - 1] == true){
live++;
}
}
if (row + 1 < grid.length) {
if(grid[row + 1][col] == true){
live++;
}
}
if (row - 1 >= 0) {
if(grid[row - 1][col] == true){
live++;
}
}
if (col + 1 < grid[col].length) {
if(grid[row][col + 1] == true){
live++;
}
}
if (col - 1 >= 0) {
if(grid[row][col - 1] == true){
live++;
}
}
if (grid[row][col] == true && live == 2 || live == 3) {
newGrid[row][col] = true;
} else {
newGrid[row][col] = false;
}
}
}
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[col].length; col++) {
live = 0;
if (row - 1 >= 0 || col - 1 >= 0) {
if(grid[row - 1][col - 1] == false){
live++;
}
}
if (row + 1 < grid.length || col + 1 < grid[col].length) {
if(grid[row + 1][col + 1] == false){
live++;
}
}
if (row - 1 >= 0 || col + 1 < grid[col].length) {
if(grid[row - 1][col + 1] == false){
live++;
}
}
if (row + 1 < grid.length || col - 1 >= 0) {
if(grid[row + 1][col - 1] == false ){
live++;
}
}
if (row + 1 < grid.length) {
if(grid[row + 1][col] == false ){
live++;
}
}
if (row - 1 >= 0) {
if(grid[row - 1][col] == false){
live++;
}
}
if (col + 1 < grid[col].length) {
if(grid[row][col + 1] == false){
live++;
}
}
if (col - 1 >= 0) {
if(grid[row][col - 1] == false){
live++;
}
}
if (live == 3) {
newGrid[row][col] = true;
} else {
newGrid[row][col] = false;
}
}
}
}
public void runGame(int foo) {
for (int poo = 0; poo < foo; poo++) {
runRound();
}
}
}
The main problem you have is that your bounds checks are "or" logic: you go ahead with the computation if either row or col is in bounds. You need to have them both in bounds; use an and.
If you're tired of that, you can get a similar effect by padding your entire grid with false values, one layer on each side. Your actual cells are in the range 1 through grid.length+1; row/col 0 and grid.length+2 are false.
This code is part of the code for my Conway's Game of Life simulation. This particular method is a 'step', advancing the game forward by one generation.
There seems to be an error when it attempts to check if the square straight up is true or false (this is a 10 x 10 boolean array at the moment). The code's intention is to check every square and count how many neighbors each square has. I have if statements making it so that the squares on the edges and corners go under special conditions (e.g. the one in the top right doesn't check for the squares straight up, top right, and directly right)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Life.step(Life.java:71)
The error is above and Line 71 is the if statement that checks for a neighbor straight down
public void step() {
System.out.println("Step");
System.out.println(cells.length);
System.out.println(cells[0].length);
boolean[][] nextCells = new boolean[cells.length][cells[0].length];
for (int row = 0; row < cells.length; row++) {
for (int col = 0; row < cells[0].length; col++) {
int neighborCount = 0;
// checks for neighbor straight down
if (row > 0 && cells[row - 1][col] == true) {
neighborCount++;
}
// lower right
if (row > 0 && col < cells[0].length - 1 && cells[row - 1][col + 1] == true) {
neighborCount++;
}
// right
if (col < cells[0].length - 1 && cells[row][col + 1] == true) {
neighborCount++;
}
// upper right
if (row < cells.length - 1 && col < cells[0].length - 1 && cells[row + 1][col + 1] == true) {
neighborCount++;
}
// straight up
if (row < cells.length - 1 && cells[row + 1][col] == true) {
neighborCount++;
}
// upper left
if (row < cells.length - 1 && col > 0 && cells[row + 1][col - 1] == true) {
neighborCount++;
}
// left
if (col > 0 && cells[row][col - 1] == true) {
neighborCount++;
}
// lower left
if (row > 0 && col > 0 && cells[row - 1][col - 1]) {
neighborCount++;
}
Look at the line above where the error is being thrown:
for (int col = 0;row< cells[0].length; col++) {
This should be:
for (int col = 0;col< cells[row].length; col++) {
// Counts the neighbors of alive or dead cells in boolean grid.
public static int countNeighbors ( final boolean[][] grid, final int row, final int col ) {
// Finds neighbors in top row.
int count = 0;
for (int i = 1; i > -1; --i) {
if (grid[row - 1][col + i] == true)
count += 1;
else if (grid[row - 1][col + i] == false)
count += 0;
}
// Finds neighbors in same row.
for (int i = 1; i > -1; --i) {
if (grid[row][col + i] == true)
count += 1;
else if (grid[row][col + i] == false)
count += 0;
}
// Finds neighbors in bottom row.
for (int i = 1; i > -1; --i) {
if (grid[row + 1][col + i] == true)
count += 1;
else if (grid[row + 1][col + i] == false)
count += 0;
}
return count;
}
Getting an array out of bounds exception when I attempt to find all true neighbor values in all 8 blocks around the specified square.
I figured the code would already handle if it was out of bounds as I assume those values would be false anyways.
Create a separate function to get the grid cell, including a bounds check:
public static boolean getGridCell ( final boolean[][] grid, final int row, final int col )
{
// bounds check:
if((row < 0) || (row >= grid.length))
return false;
if((col < 0) || (col >= grid[row].length))
return false;
return grid[row][col];
}
Then call this function instead of accessing the grid directly:
public static int countNeighbors ( final boolean[][] grid, final int row, final int col ) {
// Finds neighbors in top row.
int count = 0;
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row - 1,col + i))
count += 1;
}
// Finds neighbors in same row.
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row, col + i))
count += 1;
}
// Finds neighbors in bottom row.
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row + 1, col + i))
count += 1;
}
return count;
}
Also:
There's no need to check if the grid cell is empty and add zero to count if it is, because that isn't going to make any difference to the count.
You don't need to test if(some_boolean == true), you can just write if(some_boolean)
Your loop termination condition should be >= -1 not > -1, if you intend include -1.
(this is a 2d array filled with objects) So the places marked "//Out of Grid" is where I don't know how to tell java that the index its looking for is not in the grid and to move on.
A basic over view of what im trying to accomplish is go thru each cell starting[0][0] and check all of its adjacent neighbors, as for the first check its neighbors would be [0][1],[1][0], and [1][1]. and then if the age of the object in the index is 0, do something..
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
int neighbor_x = x + i;
int neighbor_y = y + j;
if (neighbor_x < 0 || neighbor_x >= board.length) {
// Out of Grid
}
if (neighbor_y < 0 || neighbor_y >= board[neighbor_x].length) {
// Out of Grid
}
if (board[neighbor_x][neighbor_y].age == 0) {
nCount++;
if (board[x + i][y + j].getPreviousValue() == 0)
hCount++;
}
}
}
Unless you want to perform some operations, you can simply leave them out.
Out of bound exception can occur in the case where neighbor_x < 0 and neighbor_y >=0, when the second statement is being ran, the first condition is verified and the second throws an exception. You can simply use the only condition that matters
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
int neighbor_x = x + i;
int neighbor_y = y + j;
if ((neighbor_x >=0 && neighbor_x < board.length) &&
(neighbor_y >= 0 && neighbor_y < board[neighbor_x].length) &&
board[neighbor_x][neighbor_y].age == 0 ) {
nCount++;
if (board[x + i][y + j].getPreviousValue() == 0)
hCount++;
}
}
}
If this ever throws an exception, then just separate the conditions comme suite
if ( neighbor_x >=0 && neighbor_x < board.length )
if(neighbor_y >= 0 && neighbor_y < board[neighbor_x].length)
if(board[neighbor_x][neighbor_y].age == 0 )