Recursive Sudoku Solver
I just finished up a program which takes a byte[9][9]
as input and recursively does a DFS to find any solutions (including multiple solutions). I'm pretty happy with it and it works pretty quickly as far as I can tell. I'm mainly looking for advice on the algorithm I used and its efficiency, as well as the way I handled return values, but any advice is appreciated.
The algorithm:
- Generate a
byte[9][9]
with each cell value representing the # of possible values that can be placed in that spot on the sudoku grid. - Check each cell in the possible values grid. If it is 1, then there is only one possible value - enter this into the sudoku grid.
- If a value was changed in 2, repeat 1-2 with the updated possible values grid.
- If the grid is full, it is solved; return it. If the grid has empty cells, but zero possible values, it is invalid; return an empty
byte[1][1]
. Otherwise, continue to 5. - Once there are no more 1's in the possible values grid, find a cell with the least possible values
n
(usually 2 or 3) and createn
copies of the sudoku grid, filling in the cell of each with each of the possible values.
Call the same function on each of these grid, and if the return value is not an emptybyte[1][1]
, return it because it is the solution.
It seems very roundabout to have to return a byte[1][1]
but I can't think of a better way to still satisfy the return type.
public byte solve(byte g) {
byte grid = twoDimensionalCopy(g);
byte numPossible = getNumPossible(grid);
// Fills cells where only one value is possible.
// If a new value is added at any point in the loop, repeats the loop until there are no cells with only one possible value.
boolean valueAdded = false;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
// If the grid is full, then it must be a solution since all values added are first checked to be valid.
if (isFull(grid)) {
return grid;
}
else {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
// If there exists an empty cell on the grid with no possible values, return an empty byte.
if (cellEmpty(row, col, grid)
&& getPossibleValues(row, col, grid).size() == 0) {
return new byte[1][1];
}
}
}
// If neither of the above cases works, find a cell with the least number of possible values.
int lowestPossible = -1;
int lowestRow = -1;
int lowestCol = -1;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if ((lowestPossible == -1 && cellEmpty(row, col, grid))
|| (numPossible[row][col] != 0 && numPossible[row][col] < lowestPossible)) {
lowestRow = row;
lowestCol = col;
lowestPossible = numPossible[row][col];
}
}
}
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
// For each of the possible values for the cell, enter the value in the grid and call the function again. Add all the results to the ArrayList, then return the ArrayList.
for (byte pValue : pValues) {
byte newGrid = twoDimensionalCopy(grid);
enterValue(pValue, lowestRow, lowestCol, newGrid);
newGrid = solve(newGrid);
if (newGrid[0][0] != 0){
return newGrid;
}
}
}
return new byte[1][1];
}
private byte getNumPossible(byte grid) {
// Returns a byte with cells representing the number of possible values for each cell.
}
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
// Returns an ArrayList with all the possible values for a given cell.
}
private boolean anyHas(int value, int row, int col, byte grid) {
// Returns true if a cell in the same row, column, or section has the same value as the given one.
}
java algorithm recursion sudoku
add a comment |
I just finished up a program which takes a byte[9][9]
as input and recursively does a DFS to find any solutions (including multiple solutions). I'm pretty happy with it and it works pretty quickly as far as I can tell. I'm mainly looking for advice on the algorithm I used and its efficiency, as well as the way I handled return values, but any advice is appreciated.
The algorithm:
- Generate a
byte[9][9]
with each cell value representing the # of possible values that can be placed in that spot on the sudoku grid. - Check each cell in the possible values grid. If it is 1, then there is only one possible value - enter this into the sudoku grid.
- If a value was changed in 2, repeat 1-2 with the updated possible values grid.
- If the grid is full, it is solved; return it. If the grid has empty cells, but zero possible values, it is invalid; return an empty
byte[1][1]
. Otherwise, continue to 5. - Once there are no more 1's in the possible values grid, find a cell with the least possible values
n
(usually 2 or 3) and createn
copies of the sudoku grid, filling in the cell of each with each of the possible values.
Call the same function on each of these grid, and if the return value is not an emptybyte[1][1]
, return it because it is the solution.
It seems very roundabout to have to return a byte[1][1]
but I can't think of a better way to still satisfy the return type.
public byte solve(byte g) {
byte grid = twoDimensionalCopy(g);
byte numPossible = getNumPossible(grid);
// Fills cells where only one value is possible.
// If a new value is added at any point in the loop, repeats the loop until there are no cells with only one possible value.
boolean valueAdded = false;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
// If the grid is full, then it must be a solution since all values added are first checked to be valid.
if (isFull(grid)) {
return grid;
}
else {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
// If there exists an empty cell on the grid with no possible values, return an empty byte.
if (cellEmpty(row, col, grid)
&& getPossibleValues(row, col, grid).size() == 0) {
return new byte[1][1];
}
}
}
// If neither of the above cases works, find a cell with the least number of possible values.
int lowestPossible = -1;
int lowestRow = -1;
int lowestCol = -1;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if ((lowestPossible == -1 && cellEmpty(row, col, grid))
|| (numPossible[row][col] != 0 && numPossible[row][col] < lowestPossible)) {
lowestRow = row;
lowestCol = col;
lowestPossible = numPossible[row][col];
}
}
}
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
// For each of the possible values for the cell, enter the value in the grid and call the function again. Add all the results to the ArrayList, then return the ArrayList.
for (byte pValue : pValues) {
byte newGrid = twoDimensionalCopy(grid);
enterValue(pValue, lowestRow, lowestCol, newGrid);
newGrid = solve(newGrid);
if (newGrid[0][0] != 0){
return newGrid;
}
}
}
return new byte[1][1];
}
private byte getNumPossible(byte grid) {
// Returns a byte with cells representing the number of possible values for each cell.
}
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
// Returns an ArrayList with all the possible values for a given cell.
}
private boolean anyHas(int value, int row, int col, byte grid) {
// Returns true if a cell in the same row, column, or section has the same value as the given one.
}
java algorithm recursion sudoku
add a comment |
I just finished up a program which takes a byte[9][9]
as input and recursively does a DFS to find any solutions (including multiple solutions). I'm pretty happy with it and it works pretty quickly as far as I can tell. I'm mainly looking for advice on the algorithm I used and its efficiency, as well as the way I handled return values, but any advice is appreciated.
The algorithm:
- Generate a
byte[9][9]
with each cell value representing the # of possible values that can be placed in that spot on the sudoku grid. - Check each cell in the possible values grid. If it is 1, then there is only one possible value - enter this into the sudoku grid.
- If a value was changed in 2, repeat 1-2 with the updated possible values grid.
- If the grid is full, it is solved; return it. If the grid has empty cells, but zero possible values, it is invalid; return an empty
byte[1][1]
. Otherwise, continue to 5. - Once there are no more 1's in the possible values grid, find a cell with the least possible values
n
(usually 2 or 3) and createn
copies of the sudoku grid, filling in the cell of each with each of the possible values.
Call the same function on each of these grid, and if the return value is not an emptybyte[1][1]
, return it because it is the solution.
It seems very roundabout to have to return a byte[1][1]
but I can't think of a better way to still satisfy the return type.
public byte solve(byte g) {
byte grid = twoDimensionalCopy(g);
byte numPossible = getNumPossible(grid);
// Fills cells where only one value is possible.
// If a new value is added at any point in the loop, repeats the loop until there are no cells with only one possible value.
boolean valueAdded = false;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
// If the grid is full, then it must be a solution since all values added are first checked to be valid.
if (isFull(grid)) {
return grid;
}
else {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
// If there exists an empty cell on the grid with no possible values, return an empty byte.
if (cellEmpty(row, col, grid)
&& getPossibleValues(row, col, grid).size() == 0) {
return new byte[1][1];
}
}
}
// If neither of the above cases works, find a cell with the least number of possible values.
int lowestPossible = -1;
int lowestRow = -1;
int lowestCol = -1;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if ((lowestPossible == -1 && cellEmpty(row, col, grid))
|| (numPossible[row][col] != 0 && numPossible[row][col] < lowestPossible)) {
lowestRow = row;
lowestCol = col;
lowestPossible = numPossible[row][col];
}
}
}
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
// For each of the possible values for the cell, enter the value in the grid and call the function again. Add all the results to the ArrayList, then return the ArrayList.
for (byte pValue : pValues) {
byte newGrid = twoDimensionalCopy(grid);
enterValue(pValue, lowestRow, lowestCol, newGrid);
newGrid = solve(newGrid);
if (newGrid[0][0] != 0){
return newGrid;
}
}
}
return new byte[1][1];
}
private byte getNumPossible(byte grid) {
// Returns a byte with cells representing the number of possible values for each cell.
}
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
// Returns an ArrayList with all the possible values for a given cell.
}
private boolean anyHas(int value, int row, int col, byte grid) {
// Returns true if a cell in the same row, column, or section has the same value as the given one.
}
java algorithm recursion sudoku
I just finished up a program which takes a byte[9][9]
as input and recursively does a DFS to find any solutions (including multiple solutions). I'm pretty happy with it and it works pretty quickly as far as I can tell. I'm mainly looking for advice on the algorithm I used and its efficiency, as well as the way I handled return values, but any advice is appreciated.
The algorithm:
- Generate a
byte[9][9]
with each cell value representing the # of possible values that can be placed in that spot on the sudoku grid. - Check each cell in the possible values grid. If it is 1, then there is only one possible value - enter this into the sudoku grid.
- If a value was changed in 2, repeat 1-2 with the updated possible values grid.
- If the grid is full, it is solved; return it. If the grid has empty cells, but zero possible values, it is invalid; return an empty
byte[1][1]
. Otherwise, continue to 5. - Once there are no more 1's in the possible values grid, find a cell with the least possible values
n
(usually 2 or 3) and createn
copies of the sudoku grid, filling in the cell of each with each of the possible values.
Call the same function on each of these grid, and if the return value is not an emptybyte[1][1]
, return it because it is the solution.
It seems very roundabout to have to return a byte[1][1]
but I can't think of a better way to still satisfy the return type.
public byte solve(byte g) {
byte grid = twoDimensionalCopy(g);
byte numPossible = getNumPossible(grid);
// Fills cells where only one value is possible.
// If a new value is added at any point in the loop, repeats the loop until there are no cells with only one possible value.
boolean valueAdded = false;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
// If the grid is full, then it must be a solution since all values added are first checked to be valid.
if (isFull(grid)) {
return grid;
}
else {
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
// If there exists an empty cell on the grid with no possible values, return an empty byte.
if (cellEmpty(row, col, grid)
&& getPossibleValues(row, col, grid).size() == 0) {
return new byte[1][1];
}
}
}
// If neither of the above cases works, find a cell with the least number of possible values.
int lowestPossible = -1;
int lowestRow = -1;
int lowestCol = -1;
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if ((lowestPossible == -1 && cellEmpty(row, col, grid))
|| (numPossible[row][col] != 0 && numPossible[row][col] < lowestPossible)) {
lowestRow = row;
lowestCol = col;
lowestPossible = numPossible[row][col];
}
}
}
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
// For each of the possible values for the cell, enter the value in the grid and call the function again. Add all the results to the ArrayList, then return the ArrayList.
for (byte pValue : pValues) {
byte newGrid = twoDimensionalCopy(grid);
enterValue(pValue, lowestRow, lowestCol, newGrid);
newGrid = solve(newGrid);
if (newGrid[0][0] != 0){
return newGrid;
}
}
}
return new byte[1][1];
}
private byte getNumPossible(byte grid) {
// Returns a byte with cells representing the number of possible values for each cell.
}
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
// Returns an ArrayList with all the possible values for a given cell.
}
private boolean anyHas(int value, int row, int col, byte grid) {
// Returns true if a cell in the same row, column, or section has the same value as the given one.
}
java algorithm recursion sudoku
java algorithm recursion sudoku
edited May 9 '15 at 23:21
Jamal♦
30.3k11116226
30.3k11116226
asked May 9 '15 at 23:12
MattDs17
1457
1457
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Avoid magic numbers
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
In this code, you have three magic numbers: 9
, 8
, and -1
. The start of a solution is the declaration of a constant, which would likely happen outside the current method but in the same class:
private static final int BOARD_SIZE = 9;
Then you can use it like
for (int row = 0; row < BOARD_SIZE || ! valueAdded; row++) {
// If finished with the board and a value was added, repeat.
if (row >= BOARD_SIZE) {
row = 0;
valueAdded = false;
}
for (int col = 0; col < BOARD_SIZE; col++) {
Note that the valueAdded
check moves into the row
loop. This allows us to move the reset check to the beginning of the loop, eliminating two magic numbers: 8
(replaced by BOARD_SIZE
) and -1
. Setting row
to 0
is clearer about what it is doing than setting it to -1
so that it could be incremented to 0
.
A side effect of this is that the compiler has a chance to optimize out the second check. Note that row < BOARD_SIZE
and row >= BOARD_SIZE
are logical negations of each other. This may create a slight performance improvement, although it is unlikely to make a significant difference.
Also consider moving this section of code into its own method. This method is rather long. You could get this block of code down to a single line by abstracting it into a method that takes grid
as a parameter. Note that you'd have to move the numPossible
declaration after the method call.
An else
is unnecessary after a return
if (isFull(grid)) {
return grid;
}
else {
Since you return
in the if
clause, you can leave off the else
. The rest of the function will only be reached in the else
case anyway. This saves you a level of indent.
Declare as the interface rather than the implementation
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This works but makes your implementation difficult to modify. Unless you are using functionality limited only to that implementation, you should declare as the interface instead.
List<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This will allow you to change the implementation without changing this declaration.
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
Same thing here.
private List<Byte> getPossibleValues(int row, int col, byte grid) {
Note that if you actually wanted to only return an ArrayList
here, you could still change the first one. A List
variable will always accept any object that implements the List
interface.
You can actually go even more generic if you want.
for (byte pValue : pValues) {
This can become
for (byte pValue : getPossibleValues(lowestRow, lowestCol, grid)) {
In which case you don't need the pValues
variable.
You could declare a Grid
class
It seems very roundabout to have to return a byte[1][1] but I can't think of a better way to still satisfy the return type.
The problem here is that you are using a primitive type. If you declare a Grid
class and then have the method return a Grid
object, you can return null
on an invalid case. This would also allow you to move some operations into the Grid
class. Consider if you want to make Grid
implement Iterable
so that you can use it in the for
each form. Perhaps you don't want to engage in that level of engineering, but it does allow for some elegant solutions.
add a comment |
You can find the Sudoku Solver code in Java using backtrack - recursive mechanism in https://tutorialflow.com. Hope you will get a clear idea on this.
New contributor
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f90278%2frecursive-sudoku-solver%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Avoid magic numbers
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
In this code, you have three magic numbers: 9
, 8
, and -1
. The start of a solution is the declaration of a constant, which would likely happen outside the current method but in the same class:
private static final int BOARD_SIZE = 9;
Then you can use it like
for (int row = 0; row < BOARD_SIZE || ! valueAdded; row++) {
// If finished with the board and a value was added, repeat.
if (row >= BOARD_SIZE) {
row = 0;
valueAdded = false;
}
for (int col = 0; col < BOARD_SIZE; col++) {
Note that the valueAdded
check moves into the row
loop. This allows us to move the reset check to the beginning of the loop, eliminating two magic numbers: 8
(replaced by BOARD_SIZE
) and -1
. Setting row
to 0
is clearer about what it is doing than setting it to -1
so that it could be incremented to 0
.
A side effect of this is that the compiler has a chance to optimize out the second check. Note that row < BOARD_SIZE
and row >= BOARD_SIZE
are logical negations of each other. This may create a slight performance improvement, although it is unlikely to make a significant difference.
Also consider moving this section of code into its own method. This method is rather long. You could get this block of code down to a single line by abstracting it into a method that takes grid
as a parameter. Note that you'd have to move the numPossible
declaration after the method call.
An else
is unnecessary after a return
if (isFull(grid)) {
return grid;
}
else {
Since you return
in the if
clause, you can leave off the else
. The rest of the function will only be reached in the else
case anyway. This saves you a level of indent.
Declare as the interface rather than the implementation
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This works but makes your implementation difficult to modify. Unless you are using functionality limited only to that implementation, you should declare as the interface instead.
List<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This will allow you to change the implementation without changing this declaration.
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
Same thing here.
private List<Byte> getPossibleValues(int row, int col, byte grid) {
Note that if you actually wanted to only return an ArrayList
here, you could still change the first one. A List
variable will always accept any object that implements the List
interface.
You can actually go even more generic if you want.
for (byte pValue : pValues) {
This can become
for (byte pValue : getPossibleValues(lowestRow, lowestCol, grid)) {
In which case you don't need the pValues
variable.
You could declare a Grid
class
It seems very roundabout to have to return a byte[1][1] but I can't think of a better way to still satisfy the return type.
The problem here is that you are using a primitive type. If you declare a Grid
class and then have the method return a Grid
object, you can return null
on an invalid case. This would also allow you to move some operations into the Grid
class. Consider if you want to make Grid
implement Iterable
so that you can use it in the for
each form. Perhaps you don't want to engage in that level of engineering, but it does allow for some elegant solutions.
add a comment |
Avoid magic numbers
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
In this code, you have three magic numbers: 9
, 8
, and -1
. The start of a solution is the declaration of a constant, which would likely happen outside the current method but in the same class:
private static final int BOARD_SIZE = 9;
Then you can use it like
for (int row = 0; row < BOARD_SIZE || ! valueAdded; row++) {
// If finished with the board and a value was added, repeat.
if (row >= BOARD_SIZE) {
row = 0;
valueAdded = false;
}
for (int col = 0; col < BOARD_SIZE; col++) {
Note that the valueAdded
check moves into the row
loop. This allows us to move the reset check to the beginning of the loop, eliminating two magic numbers: 8
(replaced by BOARD_SIZE
) and -1
. Setting row
to 0
is clearer about what it is doing than setting it to -1
so that it could be incremented to 0
.
A side effect of this is that the compiler has a chance to optimize out the second check. Note that row < BOARD_SIZE
and row >= BOARD_SIZE
are logical negations of each other. This may create a slight performance improvement, although it is unlikely to make a significant difference.
Also consider moving this section of code into its own method. This method is rather long. You could get this block of code down to a single line by abstracting it into a method that takes grid
as a parameter. Note that you'd have to move the numPossible
declaration after the method call.
An else
is unnecessary after a return
if (isFull(grid)) {
return grid;
}
else {
Since you return
in the if
clause, you can leave off the else
. The rest of the function will only be reached in the else
case anyway. This saves you a level of indent.
Declare as the interface rather than the implementation
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This works but makes your implementation difficult to modify. Unless you are using functionality limited only to that implementation, you should declare as the interface instead.
List<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This will allow you to change the implementation without changing this declaration.
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
Same thing here.
private List<Byte> getPossibleValues(int row, int col, byte grid) {
Note that if you actually wanted to only return an ArrayList
here, you could still change the first one. A List
variable will always accept any object that implements the List
interface.
You can actually go even more generic if you want.
for (byte pValue : pValues) {
This can become
for (byte pValue : getPossibleValues(lowestRow, lowestCol, grid)) {
In which case you don't need the pValues
variable.
You could declare a Grid
class
It seems very roundabout to have to return a byte[1][1] but I can't think of a better way to still satisfy the return type.
The problem here is that you are using a primitive type. If you declare a Grid
class and then have the method return a Grid
object, you can return null
on an invalid case. This would also allow you to move some operations into the Grid
class. Consider if you want to make Grid
implement Iterable
so that you can use it in the for
each form. Perhaps you don't want to engage in that level of engineering, but it does allow for some elegant solutions.
add a comment |
Avoid magic numbers
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
In this code, you have three magic numbers: 9
, 8
, and -1
. The start of a solution is the declaration of a constant, which would likely happen outside the current method but in the same class:
private static final int BOARD_SIZE = 9;
Then you can use it like
for (int row = 0; row < BOARD_SIZE || ! valueAdded; row++) {
// If finished with the board and a value was added, repeat.
if (row >= BOARD_SIZE) {
row = 0;
valueAdded = false;
}
for (int col = 0; col < BOARD_SIZE; col++) {
Note that the valueAdded
check moves into the row
loop. This allows us to move the reset check to the beginning of the loop, eliminating two magic numbers: 8
(replaced by BOARD_SIZE
) and -1
. Setting row
to 0
is clearer about what it is doing than setting it to -1
so that it could be incremented to 0
.
A side effect of this is that the compiler has a chance to optimize out the second check. Note that row < BOARD_SIZE
and row >= BOARD_SIZE
are logical negations of each other. This may create a slight performance improvement, although it is unlikely to make a significant difference.
Also consider moving this section of code into its own method. This method is rather long. You could get this block of code down to a single line by abstracting it into a method that takes grid
as a parameter. Note that you'd have to move the numPossible
declaration after the method call.
An else
is unnecessary after a return
if (isFull(grid)) {
return grid;
}
else {
Since you return
in the if
clause, you can leave off the else
. The rest of the function will only be reached in the else
case anyway. This saves you a level of indent.
Declare as the interface rather than the implementation
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This works but makes your implementation difficult to modify. Unless you are using functionality limited only to that implementation, you should declare as the interface instead.
List<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This will allow you to change the implementation without changing this declaration.
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
Same thing here.
private List<Byte> getPossibleValues(int row, int col, byte grid) {
Note that if you actually wanted to only return an ArrayList
here, you could still change the first one. A List
variable will always accept any object that implements the List
interface.
You can actually go even more generic if you want.
for (byte pValue : pValues) {
This can become
for (byte pValue : getPossibleValues(lowestRow, lowestCol, grid)) {
In which case you don't need the pValues
variable.
You could declare a Grid
class
It seems very roundabout to have to return a byte[1][1] but I can't think of a better way to still satisfy the return type.
The problem here is that you are using a primitive type. If you declare a Grid
class and then have the method return a Grid
object, you can return null
on an invalid case. This would also allow you to move some operations into the Grid
class. Consider if you want to make Grid
implement Iterable
so that you can use it in the for
each form. Perhaps you don't want to engage in that level of engineering, but it does allow for some elegant solutions.
Avoid magic numbers
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
numPossible = getNumPossible(grid);
if (numPossible[row][col] == 1) {
enterValue(getPossibleValues(row, col, grid).get(0), row,
col, grid);
valueAdded = true;
}
}
// If at the end of the loop and a value was added, repeat.
if (row == 8 && valueAdded) {
row = -1;
valueAdded = false;
}
}
In this code, you have three magic numbers: 9
, 8
, and -1
. The start of a solution is the declaration of a constant, which would likely happen outside the current method but in the same class:
private static final int BOARD_SIZE = 9;
Then you can use it like
for (int row = 0; row < BOARD_SIZE || ! valueAdded; row++) {
// If finished with the board and a value was added, repeat.
if (row >= BOARD_SIZE) {
row = 0;
valueAdded = false;
}
for (int col = 0; col < BOARD_SIZE; col++) {
Note that the valueAdded
check moves into the row
loop. This allows us to move the reset check to the beginning of the loop, eliminating two magic numbers: 8
(replaced by BOARD_SIZE
) and -1
. Setting row
to 0
is clearer about what it is doing than setting it to -1
so that it could be incremented to 0
.
A side effect of this is that the compiler has a chance to optimize out the second check. Note that row < BOARD_SIZE
and row >= BOARD_SIZE
are logical negations of each other. This may create a slight performance improvement, although it is unlikely to make a significant difference.
Also consider moving this section of code into its own method. This method is rather long. You could get this block of code down to a single line by abstracting it into a method that takes grid
as a parameter. Note that you'd have to move the numPossible
declaration after the method call.
An else
is unnecessary after a return
if (isFull(grid)) {
return grid;
}
else {
Since you return
in the if
clause, you can leave off the else
. The rest of the function will only be reached in the else
case anyway. This saves you a level of indent.
Declare as the interface rather than the implementation
ArrayList<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This works but makes your implementation difficult to modify. Unless you are using functionality limited only to that implementation, you should declare as the interface instead.
List<Byte> pValues = getPossibleValues(lowestRow, lowestCol, grid);
This will allow you to change the implementation without changing this declaration.
private ArrayList<Byte> getPossibleValues(int row, int col, byte grid) {
Same thing here.
private List<Byte> getPossibleValues(int row, int col, byte grid) {
Note that if you actually wanted to only return an ArrayList
here, you could still change the first one. A List
variable will always accept any object that implements the List
interface.
You can actually go even more generic if you want.
for (byte pValue : pValues) {
This can become
for (byte pValue : getPossibleValues(lowestRow, lowestCol, grid)) {
In which case you don't need the pValues
variable.
You could declare a Grid
class
It seems very roundabout to have to return a byte[1][1] but I can't think of a better way to still satisfy the return type.
The problem here is that you are using a primitive type. If you declare a Grid
class and then have the method return a Grid
object, you can return null
on an invalid case. This would also allow you to move some operations into the Grid
class. Consider if you want to make Grid
implement Iterable
so that you can use it in the for
each form. Perhaps you don't want to engage in that level of engineering, but it does allow for some elegant solutions.
answered May 10 '15 at 17:51
mdfst13
17.4k52156
17.4k52156
add a comment |
add a comment |
You can find the Sudoku Solver code in Java using backtrack - recursive mechanism in https://tutorialflow.com. Hope you will get a clear idea on this.
New contributor
add a comment |
You can find the Sudoku Solver code in Java using backtrack - recursive mechanism in https://tutorialflow.com. Hope you will get a clear idea on this.
New contributor
add a comment |
You can find the Sudoku Solver code in Java using backtrack - recursive mechanism in https://tutorialflow.com. Hope you will get a clear idea on this.
New contributor
You can find the Sudoku Solver code in Java using backtrack - recursive mechanism in https://tutorialflow.com. Hope you will get a clear idea on this.
New contributor
New contributor
answered 39 mins ago
coder28
1
1
New contributor
New contributor
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f90278%2frecursive-sudoku-solver%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown