It definitely is super inefficient, but I wanted to try and get the "naive" solution first since I'm not very good/experienced at coding so far. Greatly appreciate your input though, thank you! Also, apologies to all as well, I should have documented the code/game better as well, and thank you to the poster above who actually did that. So here's the code again:
public int[][] solve(int[][] board) { // function returns a 2d array
if (solved? (board)) { // solved?() loops through board and returns true if no empty spaces.
return board; // Idea is to identify a board that is solved in any given recursive call
} // to the solve() method, and to stop the search here
generateValidBranches(board);
}
// In the function above, generateValidBranches(board) is reached and called if solved?(board) is false. Here, the board is not a solution (it has empty spaces), so we go into this method which will find the first empty space in the board and try all possible numbers in that spot. For each number tried in that spot, a new "sub-board" is generated, and once all numbers have been tried we filter for the sub-boards that are valid: those boards where the numbers tried do not lead to a row, column, or 3x3 grid that also contains that number tried. Once these valid sub-boards are generated, we pass them to the mutually recursive call to solve() and check if they are a solution. My idea was that this would continue until a board was generated that was a solution.
public void generateValidBranches(int[][] board) {
List<int[][]> subBoards = < method that generates valid subboards and returns them >
int i = 0;
while (i < subBoards.size()) {
solve(subBoards.get(i)); // in this loop, we pass each sub-board generated from a particular
i++; // board back into solve() to see if it's a solution. i is then
} // incremented to ensure no infinite loop occurs (as it will eventually
} // not be less than the number of sub-boards in subBoards
I hope this makes the code a little bit clearer, thanks to all the other replies so far as well!