Getting StackOverflow Error - java

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.

Related

Logic check for a 10*10 game

I am doing a game called 1010! Probably some of you have heard of it. Bascially I encouter some trouble when writing the Algorithm for clearance.
The rule is such that if any row or any column is occupied, then clear row and column respectively.
The scoring is such that each move gains a+10*b points. a is the number of square in the input piece p and b is the total number of row&column cleared.
To start, I create a two dimensional Array board[10][10], poulate each elements in the board[][] with an empty square.
In the class of Square, it has public void method of unset()-> "empty the square" & boolean status() -> "judge if square is empty"In the class of piece, it has int numofSquare -> "return the number of square in each piece for score calculation"
In particular, I don't know how to write it if both row and column are occupied as they are inter-cross each other in an two dimensional array.
It fail the test under some condition, in which some of the squares are not cleared but they should have been cleared and I am pretty sure is the logic problem.
My thinking is that:
Loop through squares in first row and first column, record the number of square that are occupied (using c and r); if both are 10, clear row&column, otherwise clear row or column or do nothing.
reset the c &r to 0, loop through square in the second row, second column…
update score.
Basically the hard part is that if I seperate clear column and clear row algorithm ,I will either judge row or column first then clear them . However, as every column contains at least one square belong to the row, and every row contains at least one square belong to the column, there will be mistake when both row and column are full.
Thanks for help.
import java.util.ArrayList;
public class GameState{
public static final int noOfSquares = 10;
// the extent of the board in both directions
public static final int noOfBoxes = 3;
// the number of boxes in the game
private Square[][] board; // the current state of the board
private Box[] boxes; // the current state of the boxes
private int score; // the current score
// initialise the instance variables for board
// all squares and all boxes are initially empty
public GameState()
{
getboard();
score = 0;
board = new Square[10][10];
for(int i =0;i<board.length;i++){
for(int j =0;j<board[i].length;j++){
board[i][j] = new Square();
}
}
boxes = new Box[3];
for(int k =0;k<boxes.length;k++){
boxes[k] = new Box();
}
}
// return the current state of the board
public Square[][] getBoard()
{
return board;
}
// return the current score
public int getScore()
{
return score;
}
// place p on the board with its (notional) top-left corner at Square x,y
// clear columns and rows as appropriate
int r =0;
int c = 0;
int rowandcolumn = 0;
for (int row=0;row<10;row++){
for (int column=0;column<10;column++) {
if (board[row][column].status() == true){
c = c + 1;
if( c == 10 ) {
rowandcolumn = rowandcolumn + 1;
for(int z=0;z<10;z++){
board[row][z].unset(); //Clear column
}
}
}
if (board[column][row].status() == true){
r = r + 1;
if( r == 10) {
rowandcolumn = rowandcolumn + 1;
for(int q=0;q<10;q++){
board[q][row].unset(); //Clear row
}
}
}
}
r=0; //reset
c=0;
}
score = score + p.numberofBox()+10*rowandcolumn;
}
how about this
void Background::liquidate(int &score){
int arr_flag[2][10]; //0 is row,1 is column。
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 10; j++)
{
arr_flag[i][j] = 1;
}
}
//column
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (arr[i][j].type == 0)
{
arr_flag[0][i] = 0;
break;
}
}
}
//row
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (arr[j][i].type == 0)
{
arr_flag[1][i] = 0;
break;
}
}
}
//clear column
for (int i = 0; i < 10; i++)
{
if (arr_flag[0][i] == 1)
{
for (int j = 0; j < 10; j++)
{
arr[i][j].Clear();
}
}
}
//clear row
for (int i = 0; i < 10; i++)
{
if (arr_flag[1][i] == 1)
{
for (int j = 0; j < 10; j++)
{
arr[j][i].Clear();
}
}
}
}
I tried to write somme code for the idea I posted
// place p on the board with its (notional) top-left corner at Square x,y
// clear columns and rows as appropriate
int r =0;
int c = 0;
int rowandcolumn = 0;
int row=FindFirstRow();
int column=FindFirstColumn();
if(row!=-1 && column!=-1)
{
rowandcolumn++;
//actions here: row found and column found
//clear row and column
clearRow(row);
clearColumn(column);
}
else if(row!=-1)
{
//only row is found
//clear row
clearRow(row);
}
else if(column!=-1)
{
//only column is found
//clear column
clearColumn(column);
}
else
{
//nothing is found
}
public void clearRow(int row)
{
for(int i=0; i<10;i++)
{
board[row][i].unset();
}
}
public void clearColumn(int column)
{
for(int i=0; i<10;i++)
{
board[i][column].unset();
}
}
//this method returns the first matching row index. If nothing is found it returns -1;
public int FindFirstRow()
{
for (int row=0;row<10;row++)
{
int r=0;
for (int column=0;column<10;column++)
{
if (board[row][column].status() == true)
{
r = r + 1;
if( r == 10)
{
//row found
return row;
}
}
}
r=0; //reset
}
//nothing found
return -1;
}
//this method returns the first matching column index. If nothing is found it returns -1;
public int FindFirstColumn()
{
for (int column=0;column<10;column++)
{
int c=0;
for (int row=0;row<10;row++)
{
if (board[row][column].status() == true)
{
c = c + 1;
if( c == 10 )
{
//matching column found
return column;
}
}
}
c=0; //reset
}
//nothing found
return -1;
}

Iterative brute-force sudoku solver

I am trying to implement an iterative Sudoku solver. To avoid recursion I used a stack, but I'm having problems with its management. The starting board is represented by a String array (variable 'input' in the following code) in which each element is composed of 3 numbers: the [row, col] and its value (i.e, "006" means that the element in the 1st line and 1st col is 6) and is translated into an array of int by the constructor. When I run it, I cannot get a solution, so there are probably mistakes in the nested for cycles. Any help is appreciated.
import java.util.ArrayList;
public class SudokuSolver {
private int[][] matrix = new int[9][9];
private String[] input = { "006", "073", "102", "131", "149", "217",
"235", "303", "345", "361", "378", "422", "465", "514", "521",
"548", "582", "658", "679", "743", "752", "784", "818", "883" };
private ArrayList<int[][]> stack = new ArrayList<>();
public SudokuSolver() {
// Building the board based on input array
for (int n = 0; n < input.length; ++n) {
int i = Integer.parseInt(input[n].substring(0, 1));
int j = Integer.parseInt(input[n].substring(1, 2));
int val = Integer.parseInt(input[n].substring(2, 3));
matrix[i][j] = val;
}
stack.add(matrix);
}
private boolean isSolution(int[][] cells) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if(cells[i][j] == 0)
return false;
}
}
return true;
}
private boolean isValid(int i, int j, int val, int[][] cells) {
for (int k = 0; k < 9; k++)
if (val == cells[k][j])
return false;
for (int k = 0; k < 9; k++)
if (val == cells[i][k])
return false;
return true;
}
private boolean iterativeSudokuSolver() {
int[][] current = null;
while(stack.size() > 0 && !isSolution(stack.get(0))) {
current = stack.remove(0);
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (current[row][col] == 0) {
for (int val = 1; val <= 9; val++) {
if (isValid(row, col, val, current)) {
current[row][col] = val;
stack.add(0, current);
break;
}
}
}
}
}
}
if (current != null && isSolution(current))
return true;
else
return false;
}
public static void main(String [] args) {
SudokuSolver sudokuSolver = new SudokuSolver();
boolean result = sudokuSolver.iterativeSudokuSolver();
if (result)
System.out.println("Sudoku solved");
else
System.out.println("Sudoku not solved");
}
}
A stack implementation by adding and removing the 0-th element of an ArrayList is a very bad idea: it forces the whole content of the array to be shifted back an forth every time. Use LinkedList or modify the end of the list.
When you add and remove the same instance of the matrix back and forth to the stack, it is still the same matrix object, even though you may call it "current" or any other name. This means that when you change something in the matrix and then remove it from your stack, the change stays there (and in every other element of your stack, which are identical links to the same object). The logic of your solution looks like it needs to store the previous state of the solution on the stack, if so - allocate a new array every time and copy the data (also not very efficient, but try starting there).
A good question has to be specific. "Why this doesn't work?" is a bad question. Fix the obvious problems first, debug, and if puzzled provide more information about the state of your program (data in, data on step #1...N, for example)

(8 Queens) Find out if a Queen fits in 2D matrix

I'm attempting to write a program which solves the 8 Queens Problem using a 2 dimensional array of booleans. I will use backtracking to find the solution. I know this is not the optimal way to solve this problem, and that I should probably go for a 1D array for simplicity, but I want to solve it this way.
Right now I'm stuck on the function which is supposed to check whether a queen fits at a given coordinate. My row, column and down-right diagonal checks work, but I can't get the down-left diagonal check to work. I'm struggling to find the correct indexes of i and j (x and y) to start at, and which counter to increment/decrement for each iteration. Right now my function looks like this:
public static boolean fits(int x, int y) {
for(int i = 0; i < N; i++) {
if(board[x][i]) {
return false; // Does not fit on the row
}
}
for(int i = 0; i < N; i++) {
if(board[i][y]) {
return false; // Does not fit on the column
}
}
for(int i = Math.max(x-y, 0), j = Math.max(y-x, 0); i < N && j < N; i++, j++) {
if(board[i][j]) {
return false; // Down right diagonal issue
}
}
for(int i = Math.min(x+y, N-1), j = Math.max(N-1-x, 0); i >= 0 && j < N; i--, j++) {
if(board[i][j]) {
return false; // Supposed to check the down-left diagonal, but does not work.
}
}
return true;
}
As you can see there's a problem with the last loop here. I'd be very, very happy if someone could give me a working for-loop to check the down-left diagonal. Thanks in advance!
Edit: Here's the working code:
public class MyQueens {
static boolean[][] board;
static final int N = 8;
public static void main(String[] args) {
int p = 0;
board = new boolean[N][N];
board[1][1] = true;
System.out.println(fits(0, 2));
System.out.println(fits(2, 2));
}
public static boolean fits(int x, int y) {
for(int i = 0; i < N; i++) {
if(board[x][i]) {
return false; // Row
}
}
for(int i = 0; i < N; i++) {
if(board[i][y]) {
return false; // Column
}
}
for(int i = 0, j = 0; i < N && j < 0; i++, j++) {
if(board[i][j]) {
return false; // for right diagonal
}
}
int mirrorx = (N-1)-x;
for(int i = Math.max(mirrorx-y, 0), j = Math.max(y-mirrorx, 0); i < N && j < N; i++, j++) {
if(board[(N-1)-i][j]) {
return false;
}
}
return true;
}
}
I'm attempting to write a program which solves the 8 Queens Problem using a 2 dimensional array of booleans.
This is not the optimal representation, because you must use four loops to check if a queen can be placed or not. A much faster way of doing it is available.
For the purposes of your program, there are four things that must be free of threats in order for a queen to be placed:
A row,
A column,
An ascending diagonal, and
A descending diagonal
Each of these four things can be modeled with a separate array of booleans. There are eight rows, eight columns, fifteen ascending diagonals, and fifteen descending diagonals (including two degenerate cases of one-cell "diagonals" in the corners).
Declare four arrays row[8], col[8], asc[15] and desc[15], and use these four methods to work with it:
public static boolean fits(int r, int c) {
return !row[r] && !col[c] && !asc[r+c] && !desc[c-r+7];
}
public static void add(int r, int c) {
set(r, c, true);
}
public static void remove(int r, int c) {
set(r, c, false);
}
private static void set(int r, int c, boolean q) {
row[r] = col[c] = asc[r+c] = desc[c-r+7] = q;
}
Just flip the board horizontally and reuse the same algorithm as for the down right diagonal:
int mirrorx = (N-1)-x;
for(int i = Math.max(mirrorx-y, 0), j = Math.max(y-mirrorx, 0); i < N && j < N; i++, j++) {
if(board[(N-1)-i][j]) {
return false;
}
}
You could re-arrange it to make it more optimal.
Why don't you just use:
for(int i = 0, j = 0; i < N && j < 0; i++, j++) {
if(board[i][j]) {
return false; // for right diagonal
}
}
Similarly:
for(int i = 0, j = N-1; i < N && j >= 0; i++, j--) {
if(board[i][j]) {
return false; // for left diagonal
}
}

count islands of zeros in a matrix

I am trying to program following well-known counting islands problem.
and it is not giving me the expected output. Where am I going wrong?
My assumption is if 0's touch 0th row or column or dimension of matrix .. it will not be treated as island
Here is my code
public class Matrix {
static int rowCount = 5;
static int columnCount = 4;
static int[][] matrix = { {1,1,1,1,1},
{1,0,0,0,1},
{1,1,1,1,1},
{1,1,1,0,1}
};
static boolean[][] visited = new boolean[rowCount][columnCount];
private static int countIslands = 0;
public static void main(String[] args) {
try{
for(int i=0; i<rowCount; i++){
for(int j=0; j<columnCount; j++){
if(matrix[i][j]==0){
checkZeros(matrix, i, j);
System.out.println("returned " + i + j);
}
}
}
System.out.println(visited);
}catch(Exception e){
}
System.out.println(countIslands);
}
private static void checkZeros(int[][] matrix2, int i, int j) {
boolean valueWithinLimits = withinLimits(i,j);
System.out.println("checking for " + i + j);
if(valueWithinLimits) && checkAlreadyVisited(i,j)){
if(matrix[i][j+1]==0){
checkZeros(matrix2, i, j+1);
}
if(matrix[i+1][j+1]==0){
checkZeros(matrix2, i+1, j+1);
}
if(matrix[i+1][j]==0){
checkZeros(matrix2, i+1, j);
}
if(matrix[i+1][j-1]==0){
checkZeros(matrix2, i-1, j-1);
}
visited[i][j] = true;
System.out.println("i reached here when ij are : " + i + j);
countIslands ++;
}
}
private static boolean checkAlreadyVisited(int i, int j) {
System.out.println("visited found for " + i + j);
return visited[i][j-1] || visited[i-1][j-1] || visited[i-1][j] || visited[i-1][j+1];
}
private static boolean withinLimits(int i, int j) {
return (i>0 && i<rowCount-1 && j>0 && j<columnCount-1);
}
}
The below solution is tested and works perfectly fine for any possibility
package com.divyanshu.island;
/**
* <b>Assumption 1 : 1 is Land, 0 is water.</b>
* <b>Assumption 2 : It is all water outside the matrix.</b>
*
* Instantiate IslandCounter by passing a m*n matrix.
* Method getIslandCount gives you the count of island formed.
*
* </br></br>Or</br></br>
*
* Method getIslandCount gives the count of all connected 1s in a m*n matrix with values in 1 or 0.
*/
public class IslandCounter {
private Integer[][] matrix;
public IslandCounter(Integer[][] matrix) {
this.matrix = matrix;
}
public int getIslandCount() {
int count = 0;
if (matrix == null || matrix.length == 0) {
return count;
}
Integer[][] tempMatrix = matrix.clone();
for (int i = 0; i < tempMatrix.length; i++) {
for (int j = 0; j < tempMatrix[i].length; j++) {
if (detectIsland(tempMatrix, false, i, j, matrix.length - 1, matrix[i].length - 1)) {
count++;
}
}
}
return count;
}
private boolean detectIsland(Integer[][] tempMatrix,
boolean islandDetected,
int i,
int j,
int iMax,
int jMax) {
if (i > iMax || j > jMax || i < 0 || j < 0 || tempMatrix[i][j] == 0) {
return islandDetected;
} else {
tempMatrix[i][j] = 0;
islandDetected = true;
detectIsland(tempMatrix, islandDetected, i - 1, j, iMax, jMax);
detectIsland(tempMatrix, islandDetected, i, j - 1, iMax, jMax);
detectIsland(tempMatrix, islandDetected, i + 1, j, iMax, jMax);
detectIsland(tempMatrix, islandDetected, i, j + 1, iMax, jMax);
}
return islandDetected;
}
}
===================================================================================
/**
*
*/
package com.divyanshu.island;
import java.util.Random;
/**
*This is a Main-Class to test the IslandCounter.
*/
public class IslandTest {
/**
* #param args
*/
public static void main(String[] args) {
Integer[][] matrix = generateMatrix();
printMatrix(matrix);
IslandCounter counter = new IslandCounter(matrix);
System.out.println("Total islands in the matrix : " + counter.getIslandCount());
}
private static Integer[][] generateMatrix() {
Integer[][] matrix = new Integer[4][4];
Random random = new Random();
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
matrix[i][j] = random.nextInt(2);
}
}
return matrix;
}
private static void printMatrix(Integer[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
}
What you can do to improve is to add an exclusion array: an array of elements that are zeros. For example, if you find a zero within limits, you can start looking around and see if there are any zeros. Keep looking until you find all of them. Then add every single one of these zeros to the exclusion array, and when you continue with the loop, make sure it skips the elements in the exclusion array. This is not code, but the outline of the logic of the program.
I think there are multiple problems in your code.
Your visited matrix is full of false, which mean that checkAlreadyVisited will always return false. Also, I don't understand why does this method checks surroundings to see if the current location is visited. Using a temporary matrix like visited is a good idea, but you should print both map to ensure that it works.
countIslands is never incremented because of the previous error, but once you'll have resolved it, it will be incremented on every call (which should match the number of 0 on your map). If you want his solution to work with the border constraint, you must apply his detectIsland on each border before the for loop.
Divyanshu's solution works, except that it counts 1 and doesn't consider that an island touching a border is not an island (as you said).
To correct your solution, the visited matrix must be a copy of the matrix before using it, checkAlreadyVisited should only scan [i][j] and not its surrondings, and you shouldn't increment countIslands at each call.
Again, print your maps at each turns and use an easier matric like:
static int[][] matrix = {{1,1,1},
{1,0,1},
{1,1,1},};
(Didn't saw this question was three monsth old... anyway, here you go)

how to check if a number I try to add already exist in the column and row?(2d arrays )

int [][]a=new int[9][9] //creates a "square" with 81 0's
How do I go about checking if a input (when filling out the array) already exist in the column or row?
For example, for the row 0, how can I make sure I don't get the number 9 two times (for instance, once on row 0, column 0 and second on row 0 column 1)? I can't seem to figure out how to go about this (all I know is that I'll probably need two for loops? and a if statement. I'm not sure how to go about the if statement tho).
public static void main(String[] args)
{
int[][] a = new int[9][9];
boolean areThereDuplicates;
int input = 9; // or any input of course
int row = 0; // or any row
int column = 0;// or any column
areThereDuplicates = checkDuplicates(input, row, column, a);
if (!areThereDuplicates) // if there are no duplicates, input value
a[row][column] = input;
}
public static boolean checkDuplicates(int numChecked, int row, int column, int[][] arr)
{
// checks row
for (int j = 0; j < arr[row].length; j++)
{
if (arr[row][j] == numChecked)
return true;
}
// checks column
for (int k = 0; k < arr.length; k++)
{
if (arr[k][column] == numChecked)
return true;
}
return false;
}
One important thing I wanted to point out is the for loop that checks the column. arr.length does not return 81; rather it returns 9. arr[row].length also returns how many columns there are in the specified row.
Quick draft, not tested but should work:
a[x][y] = newValue; // e.g. 9
return checkDuplicates(x, y, newValue); // returns true if a duplicate is found
public boolean checkDuplicates(int x, int y, int newValue) {
for (int i=0; i<9; i++) {
if (i!=x && a[i][y]==newValue)
return true;
}
for (int i=0; i<9; i++) {
if (i!=y && a[x][i]==newValue)
return true;
}
return false;
}

Categories