Reputation: 121
I know that there are a few posts like these before, but they aren't helping me. I am writing a program that can solve a sudoku. I found an algorithm here: http://www.heimetli.ch/ffh/simplifiedsudoku.html . I am trying to write it in java and starting with a console based program. It gets into an infinite loop for some reason, even though I have ways to stop it.
package sudokuSolver;
public class Solver {
static int[][] board; //teh board
static boolean solved; //if the sudoku is solved
public static void main(String[] args) throws Exception
{
//establish temporary board for now
final int[][] TUE24JAN = {{0,0,9,0,0,0,8,0,0},
{0,1,0,0,2,0,0,3,0},
{0,0,0,7,0,8,0,0,0},
{2,0,0,0,8,0,0,0,7},
{0,3,0,1,0,2,0,4,0},
{4,0,0,0,7,0,0,0,5},
{0,0,0,6,0,3,0,0,0},
{0,8,0,0,9,0,0,7,0},
{0,0,6,0,0,0,9,0,0},};
final int[][] WED25JAN = {{2,5,0,0,0,0,4,0,0},
{0,0,3,1,0,0,7,0,0},
{0,0,0,0,8,4,0,6,0},
{4,0,0,0,0,0,0,8,0},
{7,0,0,0,1,0,0,0,4},
{0,3,0,0,0,0,0,0,9},
{0,9,0,6,5,0,0,0,0},
{0,0,1,0,0,9,2,0,0},
{0,0,2,0,0,0,0,4,3},};
board = TUE24JAN;
solved = false;
printBoard();
solve(0,0);
System.out.println("\n");
printBoard();
}
public static void solve(int x, int y) throws Exception
{
//catches the end of the line
if(y > 8)
{
y = 0;
x++;
}
//catches the end of the board
if(x > 8 || solved)
{
solved = true;
return;
}
//put a number in the cell
for(int i = 1; i < 10; i++)
{
if(!inRow(x, i) && !inCol(y, i) && !inBox(x, y, i) && !solved)
{
board[x][y] = i;
solve(x, y+1);
board[x][y] = 0;
}
}
}
//returns if the value is in the specified row
public static boolean inRow(int x, int val)
{
for(int i = 0; i < 9; i++)
if(board[x][i] == val)
return true;
return false;
}
//returns whether the value is in the specified column
public static boolean inCol(int y, int val)
{
for(int i = 0; i < 9; i++)
if(board[i][y] == val)
return true;
return false;
}
//returns whether the value fits based
public static boolean inBox(int x, int y, int val)
{
int row = (x / 3) * 3;
int col = (y / 3) * 3;
for(int r = 0; r < 3; r++)
for(int c = 0; c < 3; c++)
if(board[row+r][col+c] == val)
return true;
return false;
}
public static void printBoard()
{
for(int i = 0; i < 9; i++)
{
if( i % 3 == 0)
System.out.println("----------------------");
for(int j = 0; j < 9; j++)
{
if(j % 3 == 0)
System.out.print("|");
if(board[i][j] < 10 && board[i][j] > 0)
System.out.print(board[i][j] + " ");
else
System.out.print("- ");
}
System.out.println("|");
}
System.out.print("----------------------\n");
}
}
Edit: It should not clear the cells because when it finally reaches a solution, it changes solved to true which lets it know to not change anymore values. I am not getting a stack overflow error, it just keeps running. I accidentally let it run for an hour and it was still running, it just kept repeating at one point, never hit a solved state and never hit the first recursive sequence.
As for step by step debugging, you can do that? I use eclipse, but if there's a different IDE that allows you to do a line by line run-through, could you tell me?
Upvotes: 3
Views: 426
Reputation: 647
The code sample above doesn't make use of the full potential of recursion mainly do to the global solved
variable. I didn't made a solution from scratch but rather tried to fixed what you presented so that you can see the differences. Please comment if you have any doubts.
Without debugging but with a little logging and some nice comments stated above i came up with:
package sudoku;
public class Solver {
static int[][] board; //teh board
static boolean solved; //if the sudoku is solved
public static void main(String[] args) throws Exception {
//establish temporary board for now
final int[][] TUE24JAN =
{
{0, 0, 9, 0, 0, 0, 8, 0, 0},
{0, 1, 0, 0, 2, 0, 0, 3, 0},
{0, 0, 0, 7, 0, 8, 0, 0, 0},
{2, 0, 0, 0, 8, 0, 0, 0, 7},
{0, 3, 0, 1, 0, 2, 0, 4, 0},
{4, 0, 0, 0, 7, 0, 0, 0, 5},
{0, 0, 0, 6, 0, 3, 0, 0, 0},
{0, 8, 0, 0, 9, 0, 0, 7, 0},
{0, 0, 6, 0, 0, 0, 9, 0, 0},
};
final int[][] WED25JAN =
{
{2, 5, 0, 0, 0, 0, 4, 0, 0},
{0, 0, 3, 1, 0, 0, 7, 0, 0},
{0, 0, 0, 0, 8, 4, 0, 6, 0},
{4, 0, 0, 0, 0, 0, 0, 8, 0},
{7, 0, 0, 0, 1, 0, 0, 0, 4},
{0, 3, 0, 0, 0, 0, 0, 0, 9},
{0, 9, 0, 6, 5, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 9, 2, 0, 0},
{0, 0, 2, 0, 0, 0, 0, 4, 3},
};
board = TUE24JAN;
solved = false;
printBoard();
solve(0, 0);
System.out.println("\n");
printBoard();
} // end method main
public static void solve(int x, int y) throws Exception {
//printBoard();
System.out.println(x + " : " + y);
//catches the end of the line
if (y > 8) {
y = 0;
x++;
}
//catches the end of the board
if ((x > 8) || solved) {
solved = true;
return;
}
//put a number in the cell
for (int i = 1; i < 10; i++) {
if ((board[x][y] == 0)) { // cell to be filled
if (!inRow(x, i) && !inCol(y, i) && !inBox(x, y, i)) { // can use number
board[x][y] = i;
solve(x, y + 1);
if (solved) {
return;
}
board[x][y] = 0;
}
}
else {
solve(x, y + 1);
return;
}
} // end for
} // end method solve
//returns if the value is in the specified row
public static boolean inRow(int x, int val) {
for (int i = 0; i < 9; i++) {
if (board[x][i] == val) {
return true;
}
}
return false;
}
//returns whether the value is in the specified column
public static boolean inCol(int y, int val) {
for (int i = 0; i < 9; i++) {
if (board[i][y] == val) {
return true;
}
}
return false;
}
//returns whether the value fits based
public static boolean inBox(int x, int y, int val) {
int row = (x / 3) * 3;
int col = (y / 3) * 3;
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
if (board[row + r][col + c] == val) {
return true;
}
}
}
return false;
}
public static void printBoard() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 9; i++) {
if ((i % 3) == 0) {
sb.append("----------------------\n");
}
for (int j = 0; j < 9; j++) {
if ((j % 3) == 0) {
sb.append("|");
}
if ((board[i][j] < 10) && (board[i][j] > 0)) {
sb.append(board[i][j] + " ");
}
else {
sb.append("- ");
}
}
sb.append("|\n");
}
sb.append("----------------------\n");
System.out.println(sb.toString());
/*try {
Thread.sleep(100);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
} // end method printBoard
} // end class Solver
Upvotes: 1