Stuck in Sudoku backtracking solver (Java) - java

I have been trying to figure out my mistake in the Sudoku backtracking solver for three days. The problem is from leetcode Sudoku Solver.
My solver is based on the deduction in the attached picture. The problem is that my board is changed even if a path from root to leaf is invalid.
In other words, after it goes through an invalid path, the values it attempted are fixed in my original board. However, I only update my original board when its children returns true ( see the part in helper method: // put a number and generate children).
Basically, for each '.', I generate all possibilities from 1 to 9, construct a temp board which fills the current '.' with one possibility, then call helper of the next '.' with temp board. I know it is not good to store a same size boardTemp for each possible child because of space cost, but my main concern now is to solve the problem first before optimizing the cost.
All in all, why is my board changing even if all children is not valid?
For example, base on the initial board
..9748...; 7........; .2.1.9...;
..7...24.; .64.1.59.; .98...3..;
...8.3.2.; ........6; ...2759..;
I got the final result after I run:
139748652; 745326189; 826159437;
35769.24.; .64.1.59.; .98...3..;
...8.3.2.; ........6; ...2759..;
public void sudokuSolver(char[][] board) {
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0 ; j < board.length ; j++) {
if (board[i][j] == '.') {
// find the first '.' as root
helper(i, j, board);
return;
}
}
}
}
private boolean helper(int row, int col, char[][] board) {
// case 2. check if it has following '.' and store its position
boolean hasNext = false;
boolean nextSearching = false;
int nextRow = row;
int nextCol = col;
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0; j < board.length ; j++) {
if (nextSearching && !hasNext && board[i][j] == '.') {
hasNext = true; // there is next!
nextRow = i;
nextCol = j;
}
if (i == row && j == col) {
nextSearching = true;
}
}
}
// exit condition: last '.'
if (!hasNext) {
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
return true;
}
}
return false;
}
// put a number and generate children
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
char[][] boardTemp = board;
boardTemp[row][col] = put;
boolean valid = helper(nextRow, nextCol, boardTemp);
if (valid) {
// board is supposed to change only when valid is true.
board[row][col] = put;
return true;
}
}
}
return false;
}
private boolean isValid(int row, int col, char[][] board, char c) {
// go through each row, column, and subblock to determine if c is a valid choice based on current board.
for (int jCol = 0 ; jCol < 9 ; jCol ++) {
if (board[row][jCol] == c) {
return false;
}
}
for (int iRow = 0 ; iRow < 9 ; iRow ++) {
if (board[iRow][col] == c) {
return false;
}
}
for (int i = row/3*3 ; i < row/3*3 + 3 ; i++) {
for (int j = col/3*3 ; j < col/3*3 + 3 ; j++) {
if (board[i][j] == c) {
return false;
}
}
}
return true;
}

There is no difference between using boardTemp and board. char[][] boardTemp = board means they point to the same memory... What you missed in your original code is the else part in after you put an invalid number:
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
char[][] boardTemp = board; // board and boardTemp are essentially the same thing
boardTemp[row][col] = put;
boolean valid = helper(nextRow, nextCol, boardTemp);
if (valid) {
// board is supposed to change only when valid is true.
board[row][col] = put;
return true;
}
// THIS IS WHAT YOU MISSED!!
// if you don't reset the '.' back, your later backtrack will not work
// because you put an invalid number on your board and you will never find a solution
boardTemp[row][col] = '.';
}
}

Related

Mark nodes as visited in DFS for Word Search

This is the word search problem on leetcode. I've provided a picture below that explains it well. My approach consists of a DFS on each letter in the board (by iterating through a double for loop), I'm doing this so my dfs function can start from each letter and I can get all the different words.
I'm marking the nodes as visited by also passing in a boolean array, where the value is changed to true if I've seen that node and changed back to false if it didn't lead to a path. I think this is where I'm messing up. I'm not sure how to properly mark the nodes as visited here, and if I don't then I get an infinite loop.
When I run my program and print out the strings the dfs is building, I don't get all the possible strings. This is what I'm trying to figure out, how to get all the strings.
You can run the code in leetcode as well. Thank you!
class Solution {
public boolean exist(char[][] board, String word) {
if(board == null || word == null) {
return false;
}
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
List<Character> tempList = new ArrayList<>();
tempList.add(board[i][j]);
boolean[][] tempBoard = new boolean[board.length][board[0].length];
if(wordExists(i, j, word, tempList, board, tempBoard)) {
return true;
}
else{
tempList.remove(tempList.size() - 1);
}
}
}
return false;
}
public static boolean wordExists(int sr, int sc, String word, List<Character> list, char[][] board, boolean[][] tempBoard) {
StringBuilder sb = new StringBuilder();
for(Character c : list) {
sb.append(c);
}
System.out.println(sb.toString());
if(word.equals(sb.toString())) {
return true;
}
final int[][] SHIFTS = {
{0,1},
{1,0},
{0,-1},
{-1,0}
};
tempBoard[sr][sc] = true;
for(int[] shift : SHIFTS) {
int row = sr + shift[0];
int col = sc + shift[1];
if(isValid(board, row, col, tempBoard)) {
list.add(board[row][col]);
if(wordExists(row, col, word, list, board, tempBoard)) {
return true;
}
tempBoard[sr][sc] = false;
list.remove(list.size() - 1);
}
}
return false;
}
public static boolean isValid(char[][] board, int row, int col, boolean[][] tempBoard) {
if(row >= 0 && row < board.length && col >= 0 && col < board[row].length && tempBoard[row][col] != true) {
return true;
}
return false;
}
}

Making Connect Four in Java (Dropping the checker)

Right now I'm making Connect Four in Java. I'm currently working on being able to drop the checker but I'm running into some problems. This is my code so far:
private static char board[][];
private static final int BOARD_WIDTH = 7;
private static final int BOARD_HEIGHT = 6;
private static boolean gameEnd = false;
public static void main(String[] args)
{
// Element #0 in the two-dimensional 'board' array is not used
// so that the column numbers selected by the players match
// with the actual internal element numbers of the array
board = new char[BOARD_HEIGHT + 1][BOARD_WIDTH + 1];
Scanner input = new Scanner(System.in);
char turn = 'x';
int dropColumn = 0;
System.out.println("TWO PLAYER CONNECT FOUR GAME!");
InitializeBoard();
while (gameEnd == false)
{
DisplayBoard();
dropColumn = GetDropColumn(turn, input);
if (turn == 'x')
turn = 'o';
else
turn = 'x';
if (DropChecker(turn, dropColumn) == true)
board[BOARD_HEIGHT][dropColumn] = turn;
}
}
// Set all elements of the two-dimensional 'board' array to spaces
private static void InitializeBoard()
{
char a = ' ';
for (int i = 0; i < board.length; i++)
{
board[i][0] = a;
}
for (int e = 0; e < board.length; e++)
{
board[0][e] = a;
}
}
// Display the game board (the board itself, along with the elements of
// the two-dimensional 'board' array); note that the lines of the game
// board are NOT stored in the two-dimensional 'board' array
private static void DisplayBoard()
{
for (int row = 0; row < board.length; row++)
{
for (int col = 0; col < board.length; col++)
{
System.out.print("|");
System.out.printf("%3c", board[row][col]);
}
System.out.println();
}
}
// Get (from the appropriate player) the number (1 – 'BOARD_WIDTH') of
// the column in which a checker should be dropped, and then return that
// number; if the player does not enter an integer, report the error and
// keep asking for a column number until an integer is entered; note that
// the check for an invalid column number (< 1 or > 'BOARD_WIDTH') can be
// performed in this method or in 'main', from where this method is called
private static int GetDropColumn(char turn, Scanner input)
{
int numInput = 0;
int realInput = 0;
while (realInput == 0)
{
try
{
System.out.println("Player " + turn + "'s turn: In which column would you like to place a checker? (1-7)");
numInput = input.nextInt();
if (numInput < 1 || numInput > BOARD_WIDTH)
{
numInput = 0;
System.out.println("The number was out of bounds. Please try again.");
}
}
catch (NumberFormatException e)
{
System.out.println("Invalid input. Please try again.");
}
realInput = numInput;
}
return realInput;
}
// "Drop" a checker into the designated column by setting the
// appropriate element of the two-dimensional 'board' array to
// either an 'x' or an 'o'; if the "drop" was successful, this
// method returns "true"; an attempt to "drop" the checker into
// a full column results in "false" being returned
private static boolean DropChecker(char turn, int dropColumn)
{
int count = 0;
while (count < BOARD_HEIGHT)
{
if (board[BOARD_HEIGHT - count][dropColumn] == ' ')
{
return true;
}
count++;
}
return false;
}
My problem currently is that the program won't drop the checker on the board. After I enter column 6, the program returns the board but the checker has not been dropped. What am I missing/doing wrong here?
There are a few issues with your code
The turn of the player's is reversed, so what you need to do is change the player AFTER they drop the piece, not before
The initialize board method is off, just use two for loops to initialize it
The index of placing the checker was incorrect, so start with the index at the bottom and then decrement whenever the space isn't "empty" (== ' ')
1.Main Game Loop Refactor
while (gameEnd == false)
{
DisplayBoard();
dropColumn = GetDropColumn(turn, input);
if (DropChecker(turn, dropColumn) == true)
{
turn = 'x' == turn ? 'o' : 'x'; //ternary operator works great
}
}
2.Initialize Method refactor
private static void InitializeBoard()
{
char a = ' ';
for (int i = 0; i < board.length; i++)
{
for (int e = 0; e < board[i].length; e++)
board[i][e] = a;
}
}
3.Drop Checker Method Refactor
private static boolean DropChecker(char turn, int dropColumn)
{
int indexToPaceChecker = BOARD_HEIGHT;
while (indexToPaceChecker >= 0)
{
if (board[indexToPaceChecker][dropColumn] == ' ')
{
//drop the checker, that's what this method is supposed to do anyways :)
board[indexToPaceChecker][dropColumn] = turn;
return true;
}
indexToPaceChecker--;
}
return false;
}
I'd also recommend using private static final char emptySpace = ' '; that way in your code you can intitialize the board like board[i][e] = emptySpace;, and check for an empty space like if (board[indexToPaceChecker][dropColumn] == emptySpace). It's cleaner and easier to make changes if you wanted a different board fill.
DropChecker() just checks if there is a free place in the column. Instead you should return which line is the lowest one (the one with the highest index), if there is no you could return -1.
You are setting the wrong row with the following line: board[BOARD_HEIGHT][dropColumn] = turn this puts turn into last line.
You are also not initializing your board array (if you not initialize it, it's not the same as ' ', which is also a char)
This should work for you:
private static int DropChecker(char turn, int dropColumn) {
int count = 0;
while (count < BOARD_HEIGHT) {
if (board[BOARD_HEIGHT - count][dropColumn] == ' ') {
count++;
}
else {
return --count;
}
}
}
You set the place in the board with this:
board[DropChecker(turn, dropColumn)][dropColumn]
Add this lines at the beginning of main, right after board = new char[][] :
for(int i = 0; i < BOARD_HEIGHT; i++) {
for(int j = 0; j < BOARD_WIDTH; j++) {
board[i][j] = ' ';
}
}

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;
}

(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
}
}

Getting StackOverflow Error

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.

Categories