Recursive Sudoku Solver












3














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:




  1. 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.

  2. 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.

  3. If a value was changed in 2, repeat 1-2 with the updated possible values grid.

  4. 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.

  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 create n 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 empty byte[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.
}









share|improve this question





























    3














    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:




    1. 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.

    2. 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.

    3. If a value was changed in 2, repeat 1-2 with the updated possible values grid.

    4. 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.

    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 create n 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 empty byte[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.
    }









    share|improve this question



























      3












      3








      3


      2





      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:




      1. 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.

      2. 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.

      3. If a value was changed in 2, repeat 1-2 with the updated possible values grid.

      4. 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.

      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 create n 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 empty byte[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.
      }









      share|improve this question















      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:




      1. 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.

      2. 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.

      3. If a value was changed in 2, repeat 1-2 with the updated possible values grid.

      4. 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.

      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 create n 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 empty byte[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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 9 '15 at 23:21









      Jamal

      30.3k11116226




      30.3k11116226










      asked May 9 '15 at 23:12









      MattDs17

      1457




      1457






















          2 Answers
          2






          active

          oldest

          votes


















          6














          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.






          share|improve this answer





























            -3














            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.






            share|improve this answer








            New contributor




            coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
            Check out our Code of Conduct.


















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


              }
              });














              draft saved

              draft discarded


















              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









              6














              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.






              share|improve this answer


























                6














                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.






                share|improve this answer
























                  6












                  6








                  6






                  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.






                  share|improve this answer












                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered May 10 '15 at 17:51









                  mdfst13

                  17.4k52156




                  17.4k52156

























                      -3














                      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.






                      share|improve this answer








                      New contributor




                      coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                      Check out our Code of Conduct.























                        -3














                        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.






                        share|improve this answer








                        New contributor




                        coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.





















                          -3












                          -3








                          -3






                          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.






                          share|improve this answer








                          New contributor




                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          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.







                          share|improve this answer








                          New contributor




                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          share|improve this answer



                          share|improve this answer






                          New contributor




                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          answered 39 mins ago









                          coder28

                          1




                          1




                          New contributor




                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.





                          New contributor





                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          coder28 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






























                              draft saved

                              draft discarded




















































                              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.




                              draft saved


                              draft discarded














                              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





















































                              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







                              Popular posts from this blog

                              Morgemoulin

                              Scott Moir

                              Souastre