7

Language: Java

Aim: general: Solve a sudoku game

specific: Make a recursive method solve() that:

  • Checks if number conflicts with other numbers in row, column or box
  • Fills in integer between [1-9] in given empty space if that is not the case and move to next empty space
  • (partially or fully) reverses progress if empty space can't be filled by integer between [1-9] without conflict. Then try again untill all empty spaces are filled (and sudoku is solved).

Problem: the loops try filling in integer n but will always try the lowest number first. If I were to use recursion the integers would always be the same.

Question: 1. How do you make code fill in numbers between and including 1 to 9.

  1. How do you use recursion to partially or fully erase progress and try different numbers.

  2. (extra) I've so far built code to solve a sudoku partially (until empty square can't be filled) but now it doesn't even fill in the first square even though it did earlier. It's not my main question but if anyone notices a/the issue, I would be very grateful if it were pointed out.

Reviewing: I'm reading course material on recursion but can't find the right information.

Disclaimer: All println commands outside of method printMatrix are for testing

Here's the method in question:

       // prints all solutions that are extensions of current grid
      // leaves grid in original state
void solve() {
//local variables
int[] currentSquare;
int currentRow;
int currentColumn;
boolean checkConflict;
currentSquare = new int[2];

//saftey limit for testing
int limit;
limit = 0;

while(findEmptySquare() != null){

  currentSquare = findEmptySquare().clone();
  currentRow = currentSquare[0];
  currentColumn = currentSquare[1];
  //System.out.println(" column c:"+currentColumn+" row r:"+currentRow); //column c5 r 3

  if(currentSquare[0] != -1){

    for(int n = 1; n <= ms; n++){
      checkConflict = givesConflict(currentRow, currentColumn, n);
      if(checkConflict == false){
        grid[currentRow][currentColumn] = n;
      }//end if
    }//end for
  }//end if
  else{
    System.out.println("solve: findEmptySquare was -1");
    break;
  }

  //Safety limit
  limit++;
  if (limit > 20){
    System.out.println("break");
    break;
  }//end if

}//end while
}

Here's the method that finds empty squares:

// finds the next empty square (in "reading order")
// returns array of first row then column coordinate
// if there is no empty square, returns .... (FILL IN!)
int[] findEmptySquare() {
int[] rowcol;
int[] noMoreCells;
rowcol = new int[2];
noMoreCells = new int[2];
noMoreCells[0] = -1;
noMoreCells[1] = -1;

for(int r = 0; r < ms; r++){
  for(int c = 0; c < ms; c++){
    if(grid[r][c] == 0){
      if(r != rempty || c != cempty){ //check that the location of empty cell is not the same as last one
        rempty = r;
        cempty = c;
        rowcol[0] = r; // 0 for row
        rowcol[1] = c; // 1 for column
        //System.out.println(" column c:"+rowcol[1]+" row r:"+rowcol[0]); //column c5 r 3
        return rowcol;
      }//end if
      else{
        System.out.println("findEmptySquare: found same empty square twice");
        return noMoreCells;
      }//end else
    }//end if
  }//end for
}//end for

System.out.println("findEmptySquare: no more empty cells");
return null;  //no more empty cells
}

If necessary, the entire code (indentation is messy because I had to manually add spaces on stackoverflow):

 // Alain Lifmann. Date: 26/9/2015
// Description of program: runs sudoku game
import java.util.*;

class Sudoku {
  int ms = 9; //maze Size
  int rempty; //keeping track of empty squares, row nr. (array)
  int cempty; //keeping track of empty squares, column nr. (array)
  int SIZE = 9;     // size of the grid
  int DMAX = 9;     // maximal digit to be filled in
  int BOXSIZE = 3;  // size of the boxes 
  int[][] grid;     // the puzzle grid; 0 represents empty

      // a challenge-sudoku from the web
  int[][] somesudoku = new int[][] {         
{ 0, 6, 0,   0, 0, 1,    0, 9, 4 },    //original      
  // { 0, 0, 0,   0, 0, 1,    0, 9, 4 }, //to get more solutions
{ 3, 0, 0,   0, 0, 7,    1, 0, 0 }, 
{ 0, 0, 0,   0, 9, 0,    0, 0, 0 }, 

{ 7, 0, 6,   5, 0, 0,    2, 0, 9 }, 
{ 0, 3, 0,   0, 2, 0,    0, 6, 0 }, 
{ 9, 0, 2,   0, 0, 6,    3, 0, 1 }, 

{ 0, 0, 0,   0, 5, 0,    0, 0, 0 }, 
{ 0, 0, 7,   3, 0, 0,    0, 0, 2 }, 
{ 4, 1, 0,   7, 0, 0,    0, 8, 0 }, 
  };

  // a test-sudoku from oncourse
  int[][] testsudoku = new int[][] {         
{ 1, 2, 3,   4, 5, 6,    7, 8, 9 },      
{ 4, 5, 6,   7, 8, 9,    1, 2, 3 },
{ 7, 8, 9,   1, 2, 3,    4, 5, 6 }, 

{ 2, 1, 4,   3, 6, 5,    8, 9, 7 },
{ 3, 6, 5,   8, 9, 7,    2, 1, 4 },
{ 8, 9, 7,   2, 1, 4,    3, 6, 5 },

{ 5, 3, 1,   6, 4, 2,    9, 7, 8 },
{ 6, 4, 2,   9, 7, 8,    5, 3, 1 },
{ 9, 7, 8,   5, 3, 1,    6, 4, 2 },
  };

  // a test-sudoku modified to be incomplete
  int[][] testsudoku2 = new int[][] {         
{ 0, 0, 3,   0, 5, 6,    7, 8, 0 },      
{ 0, 5, 0,   7, 0, 0,    1, 0, 3 },
{ 7, 0, 0,   1, 0, 3,    4, 5, 6 }, 

{ 2, 1, 4,   3, 6, 5,    8, 0, 7 },
{ 3, 0, 5,   8, 0, 7,    0, 1, 0 },
{ 0, 9, 7,   0, 1, 4,    3, 0, 5 },

{ 0, 0, 0,   6, 4, 2,    9, 7, 8 },
{ 0, 4, 2,   9, 7, 8,    0, 0, 1 },
{ 0, 0, 0,   5, 3, 1,    0, 4, 0 },
  };

  int solutionnr = 0; //solution counter

  // ----------------- conflict calculation --------------------

  // is there a conflict when we fill in d at position r,c?
  boolean givesConflict(int r, int  c, int d) {
if(rowConflict(r, d) == true){
  return true;
}//end if
if(colConflict(c, d) == true){
  return true;
}//end if
if(boxConflict(r, c, d) == true){
  return true;
}//end if     
return false;
  }//end givesConflict


  boolean rowConflict(int r, int d) {
    for(int i = 0; i < ms; i++){
  if(d == grid[r][i]){
    //System.out.println("rowconflict r:"+r+" d:"+d);
    return true;
  }//end if
    }//end for

    return false; //no conflict
  }

  boolean colConflict(int c, int d) {
    for(int i = 0; i < ms; i++){
  if(d == grid[i][c]){
    //System.out.println("column conflict c:"+c+" d:"+d);
    return true;
  }//end if
    }//end for

    return false; //no conflict
  }

  boolean boxConflict(int rr, int cc, int d) { //test 5,3,1
int rs; // Box-row start point
int cs; // Box-column start point
rs = rr - rr%3;
cs = cc - cc%3;
//System.out.println("box start is row "+rs+" , column "+cs);

for(int r = rs; r < rs + 3; r++ ){
  for(int c = cs; c < cs + 3; c++){

    if(d == grid[r][c]){
      //System.out.println("r:"+r+" c:"+c);
      return true;
    }//end if

  }//end for
}//end for

    return false; //no conflict
  }

  // --------- solving ----------

  // finds the next empty square (in "reading order")
  // returns array of first row then column coordinate
  // if there is no empty square, returns .... (FILL IN!)
  int[] findEmptySquare() {
int[] rowcol;
int[] noMoreCells;
rowcol = new int[2];
noMoreCells = new int[2];
noMoreCells[0] = -1;
noMoreCells[1] = -1;

    for(int r = 0; r < ms; r++){
      for(int c = 0; c < ms; c++){
    if(grid[r][c] == 0){
      if(r != rempty || c != cempty){ //check that the location of empty cell is not the same as last one
        rempty = r;
        cempty = c;
        rowcol[0] = r; // 0 for row
        rowcol[1] = c; // 1 for column
        //System.out.println(" column c:"+rowcol[1]+" row r:"+rowcol[0]); //column c5 r 3
        return rowcol;
      }//end if
      else{
        System.out.println("findEmptySquare: found same empty square twice");
        return noMoreCells;
      }//end else
    }//end if
  }//end for
    }//end for

    System.out.println("findEmptySquare: no more empty cells");
    return null;  //no more empty cells
      }

  // prints all solutions that are extensions of current
  // leaves grid in original state
  void solve() {
//local variables
int[] currentSquare;
int currentRow;
int currentColumn;
boolean checkConflict;
currentSquare = new int[2];

//saftey limit for testing
int limit;
limit = 0;

while(findEmptySquare() != null){

  currentSquare = findEmptySquare().clone();
  currentRow = currentSquare[0];
  currentColumn = currentSquare[1];
  //System.out.println(" column c:"+currentColumn+" row r:"+currentRow); //column c5 r 3

  if(currentSquare[0] != -1){

    for(int n = 1; n <= ms; n++){
      checkConflict = givesConflict(currentRow, currentColumn, n);
      if(checkConflict == false){
        grid[currentRow][currentColumn] = n;
      }//end if
    }//end for
  }//end if
  else{
    System.out.println("solve: findEmptySquare was -1");
    break;
  }

  //Safety limit
  limit++;
  if (limit > 20){
    System.out.println("break");
    break;
  }//end if

}//end while
  }

  // ------------------------- misc -------------------------

  // print the grid, 0s are printed as spaces
  void printMatrix(){
int ms; //matrix Size
ms = 9;
//layer indication symbols
String end;
String mid;
String cut;
end = "+";
mid = "-";
cut = "";
for(int i = 0; i < 2*ms-1; i++){
  cut = cut + mid;
}//end for

    System.out.println(end+cut+end);
for(int i = 0; i < ms; i++){
  if( i % 3 == 0 && i != 0){
    System.out.println(mid+cut+mid);
  }//end if
  for(int j = 0; j < ms; j++){
    if( j % 3 == 0){
      System.out.print("|");
    }//end if
    else{
      System.out.print(" ");
    }//end else
    if(grid[i][j] != 0){
      System.out.print(grid[i][j]);
    }//end if
    else{
      System.out.print(" ");
    }//end else
  }//end for j
  System.out.print("|");
  System.out.println();
}//end for i
System.out.println(end+cut+end);
  }//end method

  // reads the initial grid from stdin
  void read() {
Scanner sc = new Scanner(System.in);

for (int r=0; r<SIZE; r++) {
  if (r % BOXSIZE == 0) {
    sc.nextLine(); // read away top border of box
  }
  for (int c=0; c < SIZE; c++) {
    if (c % BOXSIZE == 0) {
      sc.next(); // read away left border of box
    }
    String square = sc.next();
    if (".".equals(square)) {
      grid[r][c] = 0;  // empty sqaure
    } else {
      grid[r][c] = Integer.parseInt(square);
    }
    //System.out.print(grid[r][c]);
  }
  sc.nextLine(); // read away right border

}
sc.nextLine(); // read away bottom border
  }

  // --------------- where it all starts --------------------




  void solveIt() {
grid = somesudoku.clone();     // set used grid (before doing anything else)
printMatrix();
solve();
printMatrix();


/* test material
 printMatrix();
 //System.out.println(givesconflict(1,1,3));
 System.out.println(rowConflict(0,1));
 System.out.println(colConflict(0,1));
 System.out.println(boxConflict(0,0,1));
 findEmptySquare();
 */
  }// end solveIt

  public static void main(String[] args) {
new Sudoku().solveIt();
  }
  }
ashiquzzaman33
  • 5,781
  • 5
  • 31
  • 42
Alain Lifmann
  • 137
  • 2
  • 9
  • 2
    The concept you're looking for is called [backtracking](https://en.wikipedia.org/wiki/Backtracking) (and is, indeed, usually implemented with recursion). – Aasmund Eldhuset Oct 21 '15 at 11:30
  • 2
    See this question. This explains an algorithm to implement backtracking http://stackoverflow.com/questions/6924216/how-to-generate-sudoku-boards-with-unique-solutions/7280517#7280517 – Mohit Oct 21 '15 at 12:00
  • Just to be sure, you want to brute force a sudoku by adding numbers until it's full or rollback if adding any number would make the sudoku impossible/wrong ? Anyway, in Aasmud Eldhuset's comment, there's a link to backtracing, and in it, there is a link to sudoku's solving algorithm with backtracking: https://en.wikipedia.org/wiki/Sudoku_solving_algorithms (the first one) – Asoub Oct 21 '15 at 12:02

1 Answers1

0

This problem can be solved by backtracking. You have to recurse through all possible option but as you encounter a wrong problem, return from that path. you can find help with code from this link http://learnfreecodes.blogspot.in/2015/11/sudoku-solver-using-backtracking-in-java.html

Saurabh Singh
  • 381
  • 5
  • 15