Backtracking | Set 7 (Sudoku)

Given a partially filled 9×9 2D array ‘grid[9][9]’, the goal is to assign digits (from 1 to 9) to the empty cells so that every row, column, and subgrid of size 3×3 contains exactly one instance of the digits from 1 to 9.

Naive Algorithm
The Naive Algorithm is to generate all possible configurations of numbers from 1 to 9 to fill the empty cells. Try every configuration one by one until the correct configuration is found.

Backtracking Algorithm
Like all other Backtracking problems, we can solve Sudoku by one by one assigning numbers to empty cells. Before assigning a number, we check whether it is safe to assign. We basically check that the same number is not present in current row, current column and current 3X3 subgrid. After checking for safety, we assign the number, and recursively check whether this assignment leads to a solution or not. If the assignment doesn’t lead to a solution, then we try next number for current empty cell. And if none of number (1 to 9) lead to solution, we return false.

  Find row, col of an unassigned cell
  If there is none, return true
  For digits from 1 to 9
    a) If there is no conflict for digit at row,col
        assign digit to row,col and recursively try fill in rest of grid
    b) If recursion successful, return true
    c) Else, remove digit and try another
  If all digits have been tried and nothing worked, return false

Following is C++ implementation for Sudoku problem. It prints the completely filled grid as output.

// A Backtracking program  in C++ to solve Sudoku problem
#include <stdio.h>

// UNASSIGNED is used for empty cells in sudoku grid
#define UNASSIGNED 0

// N is used for size of Sudoku grid. Size will be NxN
#define N 9

// This function finds an entry in grid that is still unassigned
bool FindUnassignedLocation(int grid[N][N], int &row, int &col);

// Checks whether it will be legal to assign num to the given row,col
bool isSafe(int grid[N][N], int row, int col, int num);

/* Takes a partially filled-in grid and attempts to assign values to
  all unassigned locations in such a way to meet the requirements
  for Sudoku solution (non-duplication across rows, columns, and boxes) */
bool SolveSudoku(int grid[N][N])
{
    int row, col;

    // If there is no unassigned location, we are done
    if (!FindUnassignedLocation(grid, row, col))
       return true; // success!

    // consider digits 1 to 9
    for (int num = 1; num <= 9; num++)
    {
        // if looks promising
        if (isSafe(grid, row, col, num))
        {
            // make tentative assignment
            grid[row][col] = num;

            // return, if success, yay!
            if (SolveSudoku(grid))
                return true;

            // failure, unmake & try again
            grid[row][col] = UNASSIGNED;
        }
    }
    return false; // this triggers backtracking
}

/* Searches the grid to find an entry that is still unassigned. If
   found, the reference parameters row, col will be set the location
   that is unassigned, and true is returned. If no unassigned entries
   remain, false is returned. */
bool FindUnassignedLocation(int grid[N][N], int &row, int &col)
{
    for (row = 0; row < N; row++)
        for (col = 0; col < N; col++)
            if (grid[row][col] == UNASSIGNED)
                return true;
    return false;
}

/* Returns a boolean which indicates whether any assigned entry
   in the specified row matches the given number. */
bool UsedInRow(int grid[N][N], int row, int num)
{
    for (int col = 0; col < N; col++)
        if (grid[row][col] == num)
            return true;
    return false;
}

/* Returns a boolean which indicates whether any assigned entry
   in the specified column matches the given number. */
bool UsedInCol(int grid[N][N], int col, int num)
{
    for (int row = 0; row < N; row++)
        if (grid[row][col] == num)
            return true;
    return false;
}

/* Returns a boolean which indicates whether any assigned entry
   within the specified 3x3 box matches the given number. */
bool UsedInBox(int grid[N][N], int boxStartRow, int boxStartCol, int num)
{
    for (int row = 0; row < 3; row++)
        for (int col = 0; col < 3; col++)
            if (grid[row+boxStartRow][col+boxStartCol] == num)
                return true;
    return false;
}

/* Returns a boolean which indicates whether it will be legal to assign
   num to the given row,col location. */
bool isSafe(int grid[N][N], int row, int col, int num)
{
    /* Check if 'num' is not already placed in current row,
       current column and current 3x3 box */
    return !UsedInRow(grid, row, num) &&
           !UsedInCol(grid, col, num) &&
           !UsedInBox(grid, row - row%3 , col - col%3, num);
}

/* A utility function to print grid  */
void printGrid(int grid[N][N])
{
    for (int row = 0; row < N; row++)
    {
       for (int col = 0; col < N; col++)
             printf("%2d", grid[row][col]);
        printf("\n");
    }
}

/* Driver Program to test above functions */
int main()
{
    // 0 means unassigned cells
    int grid[N][N] = {{3, 0, 6, 5, 0, 8, 4, 0, 0},
                      {5, 2, 0, 0, 0, 0, 0, 0, 0},
                      {0, 8, 7, 0, 0, 0, 0, 3, 1},
                      {0, 0, 3, 0, 1, 0, 0, 8, 0},
                      {9, 0, 0, 8, 6, 3, 0, 0, 5},
                      {0, 5, 0, 0, 9, 0, 6, 0, 0},
                      {1, 3, 0, 0, 0, 0, 2, 5, 0},
                      {0, 0, 0, 0, 0, 0, 0, 7, 4},
                      {0, 0, 5, 2, 0, 6, 3, 0, 0}};
    if (SolveSudoku(grid) == true)
          printGrid(grid);
    else
         printf("No solution exists");

    return 0;
}

Output:

  3 1 6 5 7 8 4 9 2
  5 2 9 1 3 4 7 6 8
  4 8 7 6 2 9 5 3 1
  2 6 3 4 1 5 9 8 7
  9 7 4 8 6 3 1 2 5
  8 5 1 7 9 2 6 4 3
  1 3 8 9 4 7 2 5 6
  6 9 2 3 5 1 8 7 4
  7 4 5 2 8 6 3 1 9

References:
http://see.stanford.edu/materials/icspacs106b/H19-RecBacktrackExamples.pdf

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.





  • anil

    During backtracking aren’t we modifying the original input too ??

    • anil

      ok got it, we are actually not overwriting the original input positions at all ..

  • Argha

    //A simple c++ version

    #include

    #include

    #include

    #define UNASSIGNED 0

    #define MAX 9

    using namespace std;

    class Sudoku

    {

    private:

    int A[MAX][MAX];

    public:

    static int count;

    void getPuzzle();

    void display();

    bool checkSquare(int i,int j,int x);//place for x within a Square

    bool checkRow(int i,int j,int x);//place for x within a Row

    bool checkCol(int i,int j,int x);//place for x in a Column

    bool isSafe(int i,int j,int x);//all restrictions

    bool FindUnassignedLocation(int &row, int &col);

    bool SolveSudoku();

    };

    int Sudoku::count=0;

    bool Sudoku::SolveSudoku()

    {

    count++;

    ofstream out;

    out.open(“Moments.txt”, std::ios_base::app);

    for(int i=0;i<MAX;i++)

    {

    for(int j=0;j<MAX;j++)

    {

    out<<A[i][j]<<" ";

    }

    out<<endl;

    }

    out<<endl<<endl;

    out.close();

    int row, col;

    if (FindUnassignedLocation(row, col)==false)

    return true;

    for (int num = 1; num <= 9; num++)

    {

    if (isSafe( row, col, num)==true)

    {

    A[row][col] = num;

    if (SolveSudoku()==true)

    return true;

    A[row][col] = UNASSIGNED;

    }

    }

    return false;

    }

    bool Sudoku::FindUnassignedLocation(int &row, int &col)

    {

    for (row = 0; row < MAX; row++)

    for (col = 0; col < MAX; col++)

    if (A[row][col] == UNASSIGNED)

    return true;

    return false;

    }

    bool Sudoku::isSafe(int i,int j,int x)

    {

    if(checkSquare(i,j,x)==false && checkRow(i,j,x)==false && checkCol(i,j,x)==false)

    {

    return true;

    }

    return false;

    }

    bool Sudoku::checkSquare(int i,int j,int x)

    {

    int m,n;

    m=(i/3)*3;//Trucation for proper block idejntification

    n=(j/3)*3;//Trucation for proper block idejntification

    for(int p=m;p<m+3;p++)

    {

    for(int q=n;q<n+3;q++)

    {

    if (A[p][q]==x)

    {

    return true;

    }

    }

    }

    return false;

    }

    bool Sudoku::checkRow(int i,int j,int x)

    {

    for(int p=0;p<9;p++)

    {

    if(A[i][p]==x)

    {

    return true;

    }

    }

    return false;

    }

    bool Sudoku::checkCol(int i,int j,int x)

    {

    for(int p=0;p<9;p++)

    {

    if(A[p][j]==x)

    {

    return true;

    }

    }

    return false;

    }

    void Sudoku::display()

    {

    for(int i=0;i<MAX;i++)

    {

    for(int j=0;j<MAX;j++)

    {

    cout<<A[i][j]<<" ";

    }

    cout<<endl;

    }

    }

    void Sudoku::getPuzzle()

    {

    ifstream in;

    in.open("Solve.txt");

    for(int i=0;i<MAX;i++)

    for(int j=0;j>A[i][j];

    }

    int main()

    {

    Sudoku X;

    X.getPuzzle();

    X.SolveSudoku();

    X.display();

    cout<<endl<<endl<<"Backtracking count= "<<Sudoku::count;

    getch();

    return 0;

    }

  • KK

    An improvement to FindUnassignedLocation as proposed by Skiena in The Algorithm Design Manual. This might not make any different in easy puzzles as mentioned in this page. But for the puzzle at the end of this comment, it took 20 seconds on my PC without this optimization and 1 second with it.

    int SuitableVals(int grid[N][N], int row, int col)
    {
    int total = 0;
    for (int i = 1; i < 10; i++)
    {
    if (isSafe(grid, row, col, i))
    total++;
    }
    return total;
    }

    bool FindUnassignedLocation(int grid[N][N], int &row, int &col)
    {
    int min = 10;
    int cur = 0;
    int retrow, retcol;
    bool solfound = false;
    for (retrow = 0; retrow < N; retrow++)
    {
    for (retcol = 0; retcol < N; retcol++)
    {
    if (grid[retrow][retcol] == UNASSIGNED)
    {
    solfound = true;
    cur = SuitableVals(grid, retrow, retcol);
    if (cur < min)
    {
    min = cur;
    row = retrow;
    col = retcol;
    }
    }
    }
    }
    return solfound;
    }

    Very Hard Puzzle

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

  • Shailedra

    @admin this algo. does not give solution to many sudoku puzzle…like

    {{0, 0, 6, 0, 0, 0, 0, 0, 4},
    {0, 0, 0, 8, 6, 0, 7, 3, 0},
    {0, 4, 0, 3, 5, 4, 0, 0, 2},
    {1, 7, 0, 4, 0, 0, 6, 0, 0},
    {0, 9, 0, 0, 0, 0, 0, 8, 0},
    {0, 0, 8, 0, 0, 6, 0, 1, 7},
    {2, 0, 0, 0, 8, 1, 0, 4, 0},
    {0, 6, 7, 0, 4, 3, 0, 0, 0},
    {8, 0, 0, 0, 0, 0, 3, 0, 0}} and many more test cases …
    i tried many test cases…
    i think it should include to find the min. number to get the optimal solution….

  • charamander

    I took the array b[][] to keep track of the data initially filled in the question. In this problem I gave it manually to suit the input(written at last)….b[][] contains 100 at the place already given in the quesiton and so cant be modified while solving the sudoku. I am not getting any output. I am thankful to anyone who can pull me out of this…..

    whats wrong with my fill_sudoku function????

    # include

    # include

    #define N 9

    int b[N][N]={{100, 0, 100, 100, 0, 100, 100, 0, 0},

    {100, 100, 0, 0, 0, 0, 0, 0, 0},

    {0, 100, 100, 0, 0, 0, 0, 100, 100},

    {0, 0, 100, 0, 100, 0, 0, 100, 0},

    {100, 0, 0, 100, 100, 100, 0, 0, 100},

    {0, 100, 0, 0, 100, 0, 100, 0, 0},

    {100, 100, 0, 0, 0, 0, 100, 100, 0},

    {0, 0, 0, 0, 0, 0, 0, 100, 100},

    {0, 0, 100, 100, 0, 100, 100, 0, 0}};;

    /* Returns a boolean which indicates whether any assigned entry

    in the specified row matches the given number. */

    bool UsedInRow(int grid[N][N], int row, int num)

    {

    for (int col = 0; col < N; col++)

    if (grid[row][col] == num)

    return true;

    return false;

    }

    /* Returns a boolean which indicates whether any assigned entry

    in the specified column matches the given number. */

    bool UsedInCol(int grid[N][N], int col, int num)

    {

    for (int row = 0; row < N; row++)

    if (grid[row][col] == num)

    return true;

    return false;

    }

    /* Returns a boolean which indicates whether any assigned entry

    within the specified 3×3 box matches the given number. */

    bool UsedInBox(int grid[N][N], int boxStartRow, int boxStartCol, int num)

    {

    for (int row = 0; row < 3; row++)

    for (int col = 0; col < 3; col++)

    if (grid[row+boxStartRow][col+boxStartCol] == num)

    return true;

    return false;

    }

    /* Returns a boolean which indicates whether it will be legal to assign

    num to the given row,col location. */

    bool isSafe(int grid[N][N], int row, int col, int num)

    {

    if(b[row][col]!=100)

    {

    /* Check if 'num' is not already placed in current row,

    current column and current 3×3 box */

    return !UsedInRow(grid, row, num) &&

    !UsedInCol(grid, col, num) &&

    !UsedInBox(grid, row – row%3 , col – col%3, num);

    }

    else

    return false;

    }

    void printGrid(int grid[N][N])

    {

    for (int row = 0; row < N; row++)

    {

    for (int col = 0; col < N; col++)

    printf("%2d", grid[row][col]);

    printf("n");

    }

    }

    void fill_sudoku(int grid[N][N],int row, int column)

    {

    int i=1;

    if(row==8&&column==8)

    printGrid(grid);

    if(grid[row][column]==100)

    {

    if(column==8)

    fill_sudoku(grid,row+1,0);

    else

    fill_sudoku(grid,row,column+1);

    }

    for(;i<=9;i++)

    {

    grid[row][column]=i;

    if(isSafe(grid, row, column, i)==1)

    {

    grid[row][column]=i;

    if(column==8)

    {fill_sudoku(grid,row+1,column);}

    else

    {fill_sudoku(grid,row,column+1);}

    }

    }

    }

    int main()

    {

    int grid[9][9]= {{3, 0, 6, 5, 0, 8, 4, 0, 0},

    {5, 2, 0, 0, 0, 0, 0, 0, 0},

    {0, 8, 7, 0, 0, 0, 0, 3, 1},

    {0, 0, 3, 0, 1, 0, 0, 8, 0},

    {9, 0, 0, 8, 6, 3, 0, 0, 5},

    {0, 5, 0, 0, 9, 0, 6, 0, 0},

    {1, 3, 0, 0, 0, 0, 2, 5, 0},

    {0, 0, 0, 0, 0, 0, 0, 7, 4},

    {0, 0, 5, 2, 0, 6, 3, 0, 0}};

    fill_sudoku(grid,0,0);

    return 0;

    }

  • chandeepsignh

    I copied the above code in Java but it produces the same result as the default input not the output shown above.
    Where am I making mistake? Please suggest.

  • LinuxWorld

    /* this solving the sudo ku using hashing // bashed on the // advice list and the backtracking */

    #include
    #include
    #include
    int sudoku[10][10] = { {0,0,0,0,0,0,0,0,0,0},
    {0,0,8,0,0,0,9,0,7,2},
    {0,6,0,0,0,0,0,0,0,4},
    {0,0,5,0,0,6,0,9,0,1},
    {0,2,0,0,0,0,5,0,0,0},
    {0,3,7,6,1,8,4,2,9,5},
    {0,0,0,0,3,0,0,0,0,6},
    {0,9,0,1,0,2,0,0,4,0},
    {0,5,0,0,0,0,0,0,0,9},
    {0,8,4,0,9,0,0,0,2,0}}; // very hard

    int row[10][10] = {0} ; // this matrix used for the hashing the row and the digit
    int col[10][10] = {0} ; // this is for the hashing the column
    int TCT[4][4][10] ={0} ; // three cross three (for the three cross three matrix) to hashing the 3*3 board
    int counter[10] = {0};
    int l = 0 ;
    struct advice // this take the information of about the list of the data that can be insereted into the matrix of // the sudo ku
    {
    int i , j ;
    int count ;
    int adv[10] ;
    };
    long int total ;

    typedef struct advice advice ;

    advice adv1[81] ;

    void advicearray(advice *adv) ;

    /* this method for the setting the those position that is filled already in the matrix (row , col , TCT->three cross )
    // in the TCT we are using the hasing */

    void initial()
    {
    int i , j , m,n;
    for(i = 1 ; i < 10 ;i++ )
    {
    for(j = 1 ; j < 10 ; j++)
    {
    if(sudoku[i][j])
    {
    row[i][sudoku[i][j]] = 1 ;
    col[j][sudoku[i][j]] = 1 ;
    TCT[(int)ceil((double)i/3)][(int)ceil((double)j/3)][sudoku[i][j]] = 1 ;
    }
    }
    }
    }

    // based on the initialization we can create the list of the of unfilled with and the possible input that is advice list
    void advicearray(advice *adv1)
    {
    int i , j , k , counter[10] = {0} , m ;
    l = 0 ;
    for(i = 1 ; i < 10 ;i++ )
    {
    for(j = 1 ; j < 10 ; j++)
    {
    if(!sudoku[i][j])
    {
    for(k = 1 ; k < 10 ; k++)
    counter[k] = row[i][k] || col[j][k] || TCT[(int)ceil((double)i/3)][(int)ceil((double) j/3)][k] ;

    m = 1 ;
    for(k = 1 ; k < 10 ; k++)
    {
    if(!counter[k])
    adv1[l].adv[m++] = k ;
    counter[k] = 0 ;
    }
    adv1[l].count = m ;
    adv1[l].i = i ;
    adv1[l].j = j ;
    l++ ;
    }
    }
    }

    }
    void print()
    {
    int i,j;
    for( i = 1 ; i < 10 ;i++)
    {
    for(j = 1; j < 10 ; j++)
    printf("%d \t",sudoku[i][j]) ;
    putchar('\n');
    putchar('\n');
    }
    }

    /* this is the main logic for the solving the sudo ku using hasing and the back-tracking */

    int sudoku_solver(int i , int j , int lb,int ub)
    {
    int k,p,m,num ; // next num

    if(lb == ub)
    return 1 ;

    for(k = 1 ; k < adv1[lb].count ; k++)
    { total++ ;
    num = adv1[lb].adv[k] ;
    p = row[i][num] || col[j][num] || TCT[(int)ceil((double)i/3)][(int)ceil((double) j/3)][num] ; /// checking the row col and TCT
    if(p == 0) // recursive call
    {
    sudoku[i][j] = num ;
    row[i][num] = 1 ;
    col[j][num] = 1 ;
    TCT[(int)ceil((double)i/3)][(int)ceil((double) j/3)][num] = 1;
    if(!sudoku_solver(adv1[lb+1].i , adv1[lb+1].j,lb+1,ub))
    {
    row[i][num] = 0 ;
    col[j][num] = 0 ;
    TCT[(int)ceil((double)i/3)][(int)ceil((double) j/3)][num] = 0 ;
    sudoku[i][j] = 0;
    }
    else
    return 1 ;
    }

    }
    return 0 ;

    }

    int main()
    {

    initial();
    advicearray(adv1) ;
    if(sudoku_solver(adv1[0].i , adv1[0].j , 0 , l)) ;
    print();
    return 0;
    }

  • Gengis Khan

    Never mind. I got it.

  • Gengis Khan

    There’s a bug. How are the row and col variables getting initialized? They aren’t even declared.

    • Harshit Gupta

      They are initialised by FindUnassignedLocation() …
      it took address of both.

  • http://in.linkedin.com/in/hiteshdholaria Hitesh
     
    /*
    	Title			# SUDOKU solver in C language
    	Author			# Hitesh Dholaria
    	Email			# hitesh.dholaria@gmail.com
    
    	Input 			# Following is a sample SUDOKU problem stored in the file named "problem.txt"
    					# Here, 0 represents empty place
    					# So, our overall goal is to replace such 0-places by some appropriate numbers
    					# There are total of 9 rows, 9 columns and 9 blocks of size (3x3)
    
    					008000050
    					370009010
    					000140007
    					050020600
    					001908300
    					003060020
    					700084000
    					080200063
    					090000400
    
    	Time Complexity # O(rows^2) OR O(columns^2)
    */
    
    #include<stdio.h>
    #include<conio.h>
    
    // Global array to hold main SUDOKU problem
    int A[9][9];
    
    void readProblem(void);
    void printProblem(void);
    int isProblemSolved(void);
    void eliminatePossibility(int,int);
    void getStartingIndicesOfBlock(int,int,int *,int *);
    
    // Main function
    int main() {
    
    	int counter=0,number=0;
    	int i=0,j=0,k=0,l=0,x=0,y=0;
    
    	// First read the SUDOKU input problem into A[9][9]
    	readProblem();
    	printf("----- Problem -----\n\n");
    	printProblem();
    
    	// Main loop of the program
    	// Keep running this loop, until the number of valid elements in array becomes 81
    	// That is, until problem is solved
    
    	while(!isProblemSolved()) {
    
    		// Run this loop once for each of the numbers from 1 to 9
    		// Every time increment this "number" and if it is overflown, reinitialize it to 1
    		// This "number" is like "key" or "seed" for this main loop
    
    		number++;
    		if(number>9) {
    			number=1;
    		}
    
    		// Eliminate possibility of being number at some of the 0-places by assigning -1 to those places
    
    		for(i=0;i<9;i++) {
    			for(j=0;j<9;j++) {
    				if(A[i][j]==number) {
    					eliminatePossibility(i,j);
    				}
    			}
    		}
    
    		// After eliminating possibilities,
    		// if you find any 0-place,
    		// then it means, there is a possibility of this "number" being at that place.
    		// Count such 0-places in rows,columns and blocks
    		// If it is only 1, then such 0-place must be updated by this "number",
    		// (because of no other possibility at that 0-place and wer'e 100% sure about that!)
    		
    		// Moreover, eliminate possibilities again after updation
    
    		// For all the rows
    
    		for(i=0;i<9;i++) {
    			counter=0;
    			for(j=0;j<9;j++) {
    				if(A[i][j]==0) {
    					// Save column index of this 0-place
    					k=j;
    					counter++;
    				}
    			}
    	
    			if(counter==1) {
    				A[i][k]=number;
    				eliminatePossibility(i,k);
    			}
    		}
    
    		// For all the columns
    
    		for(i=0;i<9;i++) {
    			counter=0;
    			for(j=0;j<9;j++) {
    				if(A[j][i]==0) {
    					// Save row index of this 0-place
    					k=j;
    					counter++;
    				}
    			}
    			if(counter==1) {
    				A[k][i]=number;
    				eliminatePossibility(k,i);
    			}
    		}
    
    		// For all the blocks
    
    		for(i=0;i<9;i+=3) {
    			for(j=0;j<9;j+=3) {
    				counter=0;
    				for(k=i;k<i+3;k++) {
    					for(l=j;l<j+3;l++) {
    						if(A[k][l]==0) {
    							// Save row and column indices of this 0-place
    							x=k,y=l;
    							counter++;
    						}
    					}
    				}
    				if(counter==1) {
    					A[x][y]=number;
    					eliminatePossibility(x,y);
    				}
    			}
    		}
    	}
    	// Main loop ends here
    	// Now, problem has been solved
    	// So, printing the final solution
    
    	printf("\n---- Solution ----\n\n");
    	printProblem();
    	getch();
    	return 0;
    }
    
    // This function initializes problem array A[9][9] by reading SUDOKU elements from file
    
    void readProblem(void) {
    	int i,j;
    	FILE *fp;
    	fp = fopen("problem.txt","r");
    	for(i=0;i<9;i++) {
    		for(j=0;j<9;j++) {
    			A[i][j]=fgetc(fp)-48;
    		}
    		// Skip reading '\n' into array A[9][9]
    		fgetc(fp);
    	}
    	fclose(fp);	
    }
    
    // This function prints problem array A[9][9]
    
    void printProblem(void) {
    	int i,j;
    	for(i=0;i<9;i++) {
    		for(j=0;j<9;j++) {
    			printf("%d ",A[i][j]);
    		}
    		printf("\n");
    	}
    }
    
    // This function returns 1(true), if number of valid elements(i.e. non-empty places) in A[9][9] is 81.
    // Otherwise, returns 0(false)
    // Also, note that whenever number of valid elements becomes 81,
    // that means our SUDOKU problem has been solved completely.
    
    int isProblemSolved(void) {
    	int i,j,numberOfValidElements=0;
    	for(i=0;i<9;i++) {
    		for(j=0;j<9;j++) {
    			if(A[i][j]>0) {
    				numberOfValidElements++;
    			} else {
    				A[i][j]=0;
    			}
    		}
    	}
    	if(numberOfValidElements<81) {
    		return 0;
    	} else {
    		return 1;
    	}
    }
    
    // Eliminate possibility of specific "number" being at some of the 0-places by assigning -1 to those places
    // Arguments (row,column) represents indices of any arbitrary place in A[9][9]
    
    void eliminatePossibility(int row,int column) {
    	int i,j;
    
    	// Eliminating possibility from all the rows corresponding to "column"
    	for(i=0;i<9;i++) {
    		if(A[i][column]==0) {
    			A[i][column]=-1;
    		}
    	}
    
    	// Eliminating possibility from all the columns corresponding to "row"
    	for(i=0;i<9;i++) {
    		if(A[row][i]==0) {
    			A[row][i]=-1;
    		}
    	}
    
    	// Eliminating possibility from all the places corresponding to "row" and "column"
    	getStartingIndicesOfBlock(row,column,&row,&column);
    
    	// Now, "row" and "column" contains the indices of the first element of the current block
    	for(i=row;i<row+3;i++) {
    		for(j=column;j<column+3;j++) {
    			if(A[i][j]==0) {
    				A[i][j]=-1;
    			}
    		}
    	}
    }
    
    // This function returns the indices of the first element of the 3x3 block
    // Here, specific block is being identified by the provided indices (i,j) of A[9][9]
    // Resultant indices are returned by the pointers (*rowIndex,*columnIndex) to the calling function
    
    void getStartingIndicesOfBlock(int i,int j,int *rowIndex,int *columnIndex) {
    	if(i<3) {
    		*rowIndex=0;
    	} else if(i<6) {
    		*rowIndex=3;
    	} else {
    		*rowIndex=6;
    	}
    	if(j<3) {
    		*columnIndex=0;
    	} else if(j<6) {
    		*columnIndex=3;
    	} else {
    		*columnIndex=6;
    	}
    }
     
  • minhaz

    Don’t get it, how the row and column being updated in SolveSudko function?

    • minhaz

      Oops got it.

    • rohit

      Can you please tell me how are Rows and Column getting updated

       
      /* Paste your code here (You may delete these lines if not writing code) */
       
      • vignesh m

        we are doing pass by reference hence values are updated , check signature below

         
        bool FindUnassignedLocation(int grid[N][N], int &row, int &col)
         
  • proxhotdog

    I have ported this code in ruby and it said stack level too deep (SystemStackError)

  • abc

    why row-row%3

    • abc

      Sorry understood!

      • mani

        I don’t understand. can u please explain ?

         
        /* Paste your code here (You may delete these lines if not writing code) */
         
        • mahesh

          Incase the UNASSIGNED number is 5th row we need to check if the num fits in the 3*3 block.

          5 – 5%3 = 5 – 2 = 3 (starting row of that 3*3 block)

          take for example we are updating in 8th row

          8 – 8%3 = 8 – 2 = 6 (starting row of that 3*3 block). Beautiful thinking .

  • Venki

    An interesting question would be “How can we assure that the given input is feasible?”. The situation faced by Sudoku game designers while drafting Easy, Medium and Hard puzzles.

    Any thoughts on how can we ensure minimum input which can lead to a solution? Or sufficiency of input to lead a valid solution.

    • Aashish

      @Venki,
      Bit vector can be used to ensure whether an input will
      lead to solution.
      9 bits can be used to represent any of the digits from 1 to 9[we are talking about 9×9 Sudoku,right!].
      To check whether a Cell is pre-filled & thus can’t be used for user input, it can be easily checked by ANDing the 9 bit vector with 511[2^9-1].If the result of AND operation is zero[none of the bit of the bit vector is set], the cell is empty.

      The below structure can be handy.

       
      struct mask
      {
      	int bit:9;
      };
      
      struct mask m[9][9];
       

      A 2D bit vector of size NxN[9 here] is needed to represent each cell.
      The memory has thus reduced from 9x9x4 = 324 bytes[if bit vectors are not used] to
      9x9x9/8 = 92 bytes.

      Let me know if we can do better.

      • Venki

        Whether to represent the matrix as bit vector or boolean array, or int/char array, how does it matter? We will conserve space, but all are same.

        My question is given a partially filled grid, how can we ensure that the user can successfully arrive at valid solution?

        Putting in other words, generate all possible grid permutations. Now discard the invalid grids. From the remaining grids, take any grid. Gradually remove random elements one after another from this grid. How many such random deletions can be possible? Say, we left with N elements in the grid after 81-N deletions. Can we ensure that the user will be able to fill these deleted elements? What if we delete one more element, and left with N-1 elements on the grid. Now is it possible to fill it in?

        There must be a criteria to design the puzzle. I am looking for more thoughts.

  • Diksha
     
    #include <stdio.h>
    #include <stdlib.h>
    #define SIZE 9
     
    int isValid(int (*sudoku)[SIZE],int row,int col,int weight)
    {
            int i,j,start_row,start_col;
            
            for(i=0;i<SIZE;i++)
                    if(sudoku[row][i]==weight)
                            return 0;
                            
            for(i=0;i<SIZE;i++)
                    if(sudoku[i][col]==weight)
                            return 0;
            
            start_row=(row/3)*3;
            start_col=(col/3)*3;
            for(i=start_row;i<start_row+3;i++)
                    for(j=start_col;j<start_col+3;j++)
                            if(sudoku[i][j]==weight)
                                    return 0;
                                    
            return 1;
    }
     
    void printSolution(int (*sudoku)[SIZE])
    {
            int i,j;
            printf("....................................\n");
            for(i=0;i<SIZE;i++)
            {
                    for(j=0;j<SIZE;j++)
                            printf("%d ",sudoku[i][j]);
                    printf("\n");
            }
            printf("....................................\n");
    }
     
    void solveSudoku(int (*sudoku)[SIZE],int row,int col)
    {
            int i;
            if(row==SIZE && col==0)
                    printSolution(sudoku);
            else
            {
                    if(sudoku[row][col])    //encounters a pre-filled cell.
                    {
                            solveSudoku(sudoku,row,col+1);
                            
                            if(col==SIZE-1)
                                    solveSudoku(sudoku,row+1,0);
                    }
                    else
                            for(i=1;i<=SIZE;i++)
                                    if( isValid(sudoku,row,col,i) )
                                    {
                                            sudoku[row][col]=i;
                                            
                                            solveSudoku(sudoku,row,col+1);
                                    
                                            if(col==SIZE-1)
                                                    solveSudoku(sudoku,row+1,0);
                                            
                                            sudoku[row][col]=0;
                                    }
            }
    }
     
    int main()
    {
            int sudoku[SIZE][SIZE]={{3, 0, 6, 5, 0, 8, 4, 0, 0},
                                    {5, 2, 0, 0, 0, 0, 0, 0, 0},
                                    {0, 8, 7, 0, 0, 0, 0, 3, 1},
                                    {0, 0, 3, 0, 1, 0, 0, 8, 0},
                                    {9, 0, 0, 8, 6, 3, 0, 0, 5},
                                    {0, 5, 0, 0, 9, 0, 6, 0, 0},
                                    {1, 3, 0, 0, 0, 0, 2, 5, 0},
                                    {0, 0, 0, 0, 0, 0, 0, 7, 4},
                                    {0, 0, 5, 2, 0, 6, 3, 0, 0}};;
            int i,j;
                            
            printSolution(sudoku);  //Display inputted sudoku from the file
            
            solveSudoku(sudoku,0,0);
            
            return 0;
    }
     

    See output here: http://ideone.com/8YZ4z

    • Subin

      Nice Code. Its working fine for me.
      only you have to handle col variable from going into array index out of bounds error which can be handled with one simple if case….

       
      /* Paste your code here (You may delete these lines if not writing code) */
       
    • jinzhi chen

      very nice. thanks

  • varun

    What should be the complexity for this algo..

    Let’s say total empty columns are n then I think complexity should be 9^n because for each empty box maximum tries should be 9 (1…9).

    What others think about complexity???

     
    /* Paste your code here (You may delete these lines if not writing code) */
     
    • kartik

      Yes, it should be 9^n in worst case.

    • Diksha

      Are you sure the time complexity is 9^n.
      AFAIT, each empty slot can be filled in 9 ways.
      So, the time complexity should be (no. of empty slots)^9.

      Let me know if i am missing anything.

      • Diksha

        Sorry, i misunderstood, it would be
        9^(no. of empty slots)

  • charan

    Its very explanatory. thanks for sharing :)

     
    /* Paste your code here (You may delete these lines if not writing code) */
     
    • Zheng Luo

      Very Nice Code. Thanks for sharing