Getting an out of bounds exception but do not understand why. My recursive function calls itself each time removing an item from the array list till its empty. Once its empty the row should be filled and then we add the values back to the list. I think on the final element it throws an exception because of the list length, it does not want to delete last element. Is there any way around this? Is there any chance it is a different error?
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import java.util.*;
class Main {
public static void main(String[] args) {
int[][]board=new int[9][9];
Solver solve = new Solver();
ArrayList<Integer> choices = new ArrayList<>();
choices.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9));
Collections.shuffle(choices);
for(int i = 0; i < 9; i++){
for(int j=0; j < 9; j++) {
solve.fill(board, choices, i, j);
}
}
}
}
class Solver {
public void fill(int board[][], ArrayList<Integer> choices, int
row, int col) {
int num = choices.remove(0);
if (isValid(board, row, col, num) == false) {
fill(board, choices, row, col);
} else
board[row][col] = num;
return;
}
public boolean isValid(int board[][], int row, int col, int num) {
if (checkRow(board, row, col, num) == true)
/*checkCol(board, row, col, num) == true)*/
/*checkSqr(board, row, col, num) == true*/
return true;
return false;
}
public boolean checkRow(int board[][], int row, int col, int num) {
boolean valid = true;
int i = 0;
while (i < 9) {
if (board[i][col] == num) {
return valid = false;
}
i++;
}
return valid;
}
expected result would be the board [][] being populated randomly according to the sudoku rules.
instead we get
Exception in thread "main" java.lang.IndexOutOfBoundsException:
Index 0 out of bounds for length 0
at Solver.fill(Solver.java:31)
at Main.main(Solver.java:22)
Make sure you still have an element before calling int num = choices.remove(0); you could use List.isEmpty() like
if (choices.isEmpty()) {
return;
}
int num = choices.remove(0);
I am creating a random maze generator in Java using the recursive backtracker algorithm. I need to set the edges of my maze cell data array to have been already visited by the algorithm so that it won't step out of bounds. The problem is probably staring me right in the face, I just cannot see where my error is.
Here is the whole error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 30
at mazeMaker.Maze.initBoundries(Maze.java:55)
at mazeMaker.Maze.<init>(Maze.java:46)
at mazeMaker.Main.main(Main.java:8)
I have tried tracing the error as best I could and experimented with changing my variables. The program relies on multiple class files, so I think it would be best just to show the whole thing.
Main.java
package mazeMaker;
public class Main
{
public static void main(String[] args)
{
Maze mainMaze = new Maze(20, 30);
}
}
Maze.java
package mazeMaker;
import java.util.Random;
import java.util.Stack;
public class Maze
{
public int xSize = 0;
public int ySize = 0;
public int totalDimensions = 0;
Random randomGenerator = new Random();
public Cell[][] cellData;
public Stack<Cell> cellStack = new Stack<Cell>();
Cell tempCell; // Temporary variable used for maze generation
public Maze(int xSize, int ySize)
{
cellData = new Cell[xSize][ySize];
this.xSize = xSize;
this.ySize = ySize;
this.totalDimensions = this.xSize * this.ySize;
// Initialize array objects
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j] = new Cell();
}
}
// Assign x and y positions
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j].xPos = i;
cellData[i][j].yPos = j;
}
}
initBoundries();
}
private void initBoundries()
{
// Initialize the border cells as visited so we don't go out of bounds
for (int col = 0; col < this.xSize; col++)
{
cellData[0][col].hasBeenVisited = true;
cellData[this.ySize][col].hasBeenVisited = true;
}
for (int row = 0; row < this.ySize; row++)
{
cellData[row][0].hasBeenVisited = true;
cellData[row][this.xSize].hasBeenVisited = true;
}
}
private void generateMaze(int x, int y)
{
// Set current cell as visited
cellData[x][y].hasBeenVisited = true;
// While there are unvisited neighbors
while (!cellData[x][y+1].hasBeenVisited || !cellData[x+1][y].hasBeenVisited || !cellData[x][y-1].hasBeenVisited || !cellData[x-1][y].hasBeenVisited)
{
// Select a random neighbor
while (true)
{
int r = randomGenerator.nextInt(4);
if (r == 0 && !cellData[x][y+1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasNorthWall = false;
cellData[x][y+1].hasSouthWall = false;
generateMaze(x, y + 1);
break;
}
else if (r == 1 && !cellData[x+1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasEastWall = false;
cellData[x+1][y].hasWestWall = false;
generateMaze(x+1, y);
break;
}
else if (r == 2 && !cellData[x][y-1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasSouthWall = false;
cellData[x][y-1].hasNorthWall = false;
generateMaze(x, y-1);
break;
}
else if (r == 3 && !cellData[x-1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasWestWall = false;
cellData[x-1][y].hasEastWall = false;
generateMaze(x-1, y);
break;
}
}
}
// There are no unvisited neighbors
tempCell = cellStack.pop();
generateMaze(tempCell.xPos, tempCell.yPos);
}
// Begin generating maze at top left corner
private void generateMaze()
{
generateMaze(1,1);
}
}
Cell.java
package mazeMaker;
public class Cell
{
public boolean isCurrentCell;
public boolean hasBeenVisited;
public boolean hasNorthWall;
public boolean hasSouthWall;
public boolean hasEastWall;
public boolean hasWestWall;
public int xPos;
public int yPos;
}
cellData[this.ySize][col].hasBeenVisited = true;
You have initialized your cellData as cellData[20][30], but in the above-mentioned line you are calling cellData[30][col]. Instead of 30, the first bracket should have a value from 0 to 19, because the row size is 20.
My guess is from this code in initBoundries()
// Initialize the border cells as visited so we don't go out of bounds
for (int col = 0; col < this.xSize; col++)
{
cellData[0][col].hasBeenVisited = true;
cellData[this.ySize][col].hasBeenVisited = true;
}
this.ySize after initialize (from constructor) has value 30.
I am trying to create the Game of Life with different classes, and I have gotten into trouble.
I want to check if there's an alive individual in the box with index row, col.
Here's my code so far:
public class LifeBoard {
private int rows;
private int cols;
private int generation;
/**Creates a playing field with rows as rows and cols as columns.
The counter for generations is 1.*/
public LifeBoard(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.generation = 1;
}
/**Checks if there's a living individual in the box row, col*/
public boolean get(int row, int col) {
if(this.board[row][col] == null){
return false;
} else {
return true;
}
}
}
I don't know what to do. How do I check this?
It depends on how you've modeled the game. This code assumes a boolean[][] grid.
There are up to 8 cells that surround a cell. Since we have to check for the boundaries of the grid, there might not be 8 cells surrounding every cell.
public synchronized void cycleGrid() {
this.generationCount++;
for (int i = 0; i < GRID_WIDTH; i++) {
for (int j = 0; j < GRID_WIDTH; j++) {
int count = countCells(i, j);
if (count == 3) grid[i][j] = true;
if (grid[i][j] && count < 2) grid[i][j] = false;
if (grid[i][j] && count > 3) grid[i][j] = false;
}
}
}
private int countCells(int i, int j) {
int count = 0;
int iminus = i - 1;
int jminus = j - 1;
int iplus = i + 1;
int jplus = j + 1;
if (iminus >= 0) {
if (jminus >= 0) {
if (grid[iminus][jminus]) count++;
}
if (grid[iminus][j]) count++;
if (jplus < GRID_WIDTH) {
if (grid[iminus][jplus]) count++;
}
}
if (jminus >= 0) {
if (grid[i][jminus]) count++;
}
if (jplus < GRID_WIDTH) {
if (grid[i][jplus]) count++;
}
if (iplus < GRID_WIDTH) {
if (jminus >= 0) {
if (grid[iplus][jminus]) count++;
}
if (grid[iplus][j]) count++;
if (jplus < GRID_WIDTH) {
if (grid[iplus][jplus]) count++;
}
}
return count;
}
Take a look at my article, John Conway’s Game of Life in Java Swing, for more hints.
Two things from what I have understood.
You haven't set things to NULL and you are making a check for it which wouldn't work.
You can set a check for !=NULL to return true and see if that helps.
I'm trying to write a program that takes a Sudoku puzzle and solves it.
However, I'm running into a StackOverflow error at this line:
Move nMove = new Move(current.nextMove(current, sboard).i, current.nextMove(current, sboard).j);
It has a method isLegal that checks for whether the move is valid. If move is valid and the next move is also valid, it adds it to a stack. If it is valid but the next move is not, it should keep searching for a valid number.
Not sure what's causing it.
import java.util.Stack;
public class Board {
Stack<Move> stack = new Stack<Move>();
int boardSize = 9;
public int[][] sboard = {{2,0,0,3,9,5,7,1,6},
{5,7,1,0,2,8,3,0,9},
{9,3,0,7,0,1,0,8,2},
{6,8,2,0,3,9,1,0,4},
{3,5,9,1,7,4,6,2,8},
{7,1,0,8,6,0,9,0,3},
{8,6,0,4,1,7,2,9,5},
{1,9,5,2,8,6,4,3,7},
{4,2,0,0,0,0,8,6,1}};
public Board() {
//for every cell in board:
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < boardSize; j++) {
//get the value of each cell
int temp = getCell(i,j);
//if cell is empty:
if (temp == 0) {
//print out location of cell
System.out.print ("("+i+", "+j+") ");
//guess values for that cell
solve(i, j);
}
}
}
}
//places a value into specified cell
public void setCell(int value, int row, int col) {
sboard[row][col] = value;
}
//returns value contained at specified cell
public int getCell(int row, int col) {
return sboard[row][col];
}
//if value is legal, continue
public boolean isLegal(int value, int row, int col) {
int r = (row / boardSize) * boardSize;
int c = (col / boardSize) * boardSize;
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < boardSize; j++) {
if (value == getCell(i, col) || value == getCell(row, j)) {
return false;
}
}
}
return true;
}
//guesses values for empty cells
public boolean solve(int i, int j) {
//set location as current
Move current = new Move(i, j);
Move nMove = new Move(current.nextMove(current, sboard).i, current.nextMove(current, sboard).j);
//guesses values 1 through 9 that are legal
for (int k = 1; k <= 9; k++) {
//if a legal value is found and the next move is possible:
if(isLegal(k, i, j) && solve(nMove.i, nMove.j)) {
//add current to stack
stack.push(current);
//enter the value k into the cell
setCell(k, i, j);
//print new value
System.out.print(sboard[i][j]+"\n");
//return as true
return true;
}
else if (stack.empty()){
}
//if next move is not possible
else if(!solve(nMove.i, nMove.j)){
//remove last "solved" location from stack
stack.pop();
//solve last location again
solve(stack.peek());
}
}
return false;
}
public void solve(Move m) {
solve(m.i, m.j);
}
public static void main(String[] args) {
Board b = new Board();
}
};
class Move {
int i, j;
public Move(int i, int j) {
this.i = i;
this.j = j;
}
public int i() { return i;}
public int j() { return j;}
public Move nextMove(Move current, int[][] sboard){
for (int i = current.i; i < 9; i++) {
for (int j = current.j; j < 9; j++) {
//get the value of each cell
int temp = sboard[i][j];
if (temp == 0) {
return new Move(i, j);
}
}
}
return current;
}
};
For one, it seems redundant to me to have this function in the form current.nextMove(current, board). You can either make this function static, or remove the Move current parameter.
But taking a look at your solve(i, j) function, you essentially have this:
Assume sboard[i][j] = 0 (which it clearly does, in some cases, from your input).
Assume you call solve(i, j).
current will be new Move(i, j).
nMove will then also be new Move(i, j) (since in Move#nextMove,
you essentially say if sboard[i][j] == 0, which it does from step
1).
You will end up calling solve(nMove.i, nMove.j)
Since nMove.i == i and nMove.j == j, you are essentially calling solve(i, j) over again.
Since you're calling the same function with the same parameter, and you're not reaching any base case, you will end up with a stack overflow.
As you have defined an (explicit) stack, you should not call solve() recursively.
Just loop, pop a board, generate all valid next moves, see if one of them is a solution, and if not, push them on the stack.
(I couldn't find where you verify that the board is complete, but I am probably tired.)
Btw, the stack should probably be a Dequeue. I believe a stack is synchronized which slows down the code.
Hi can anyone tell me what im doing wrong here?
i want to check each subgrid for repeated values in a 9by 9 square.
my method works first by creating each subgrid a one dimensional array which can then check each row for each subgrid. and for it to go to each subgrid i provide its coordinates myself.
it checks the first grid 0,0 but does not check other subgrids for repeated values.
can anyone tell me what im doing wrong?
public class SudokuPlayer
{
private int [][] game;
public enum CellState { EMPTY, FIXED, PLAYED };
private CellState[][] gamestate;
private int [][] copy;
private static final int GRID_SIZE=9;
private boolean whichGameToReset;
private int len;
private int stateSize;
private int row;
private int col;
private boolean coordinates(int startX, int startY)
{
row=startX;
col=startY;
if(isBoxValid()==false)
{
return false;
}
return true;
}
public boolean check()
{
if(coordinates(0,0)==false)
{
return false;
}
if(coordinates(0,3)==false)
{
return false;
}
if(coordinates(0,6)==false)
{
return false;
}
if(coordinates(1,0)==false)
{
return false;
}
if( coordinates(1,3)==false)
{
return false;
}
if( coordinates(1,6)==false)
{
return false;
}
if(coordinates(2,0)==false)
{
return false;
}
if(coordinates(2,3)==false)
{
return false;
}
if(coordinates(2,6)==false)
{
return false;
}
return true;
}
private boolean isBoxValid()
{
int[] arrayCopy = new int[game.length];
int currentRow = (row/3)*3;
int currentCol = (col/3)*3;
int i = 0;
for ( int r =currentRow; r < 3; r++)
{
for( int c =currentCol; c < 3; c++)
{
arrayCopy[i] = game[r][c];
i++;
}
}
for ( int p =0; p < arrayCopy.length; p++)
{
for ( int j = p+1; j < arrayCopy.length; j++)
{
if ( arrayCopy[p] == arrayCopy[j] && arrayCopy[j]!=0)
{
return false;
}
}
}
return true;
}
}
The problem is in your isBoxValid() method. You are initializing r and c to be currentRow and currentCol, respectively, but you run the loop up to a hard coded value of 3, not 3+currentRow or 3+currentCol. When currentRow and currentCol are 0, it works fine, but for other numbers, not so much.
Oh, another thing that's nice about writing concise code: it's easier to see where your errors are. Take another look at the numbers you've hard-coded into check(): you're incrementing the columns by 3 and the rows by 1. That would be much easier to spot if you compressed it into a pair of for loops.