简体   繁体   中英

Recursive Backtracking Algorithm in C to solve a Sudoku

I have to implement the solve method recursive in the sudoku.c for university.
I tried hard but all my implementations did not work.
I am an absolute newbie in programming c and so I despair on working with this Sudoku backtracking algorithm.

Can somebody help me?

The solve method was empty, so everything what's inside this method are just tries from me.

sudoku.h

#ifndef _SUDOKU_H_
#define _SUDOKU_H_

#define SIZE 9
#define SQRT_SIZE 3

void init(int begin[SIZE][SIZE]);
void print();
int checkValueInField(int value, int row, int col);
int setValueInField(int value, int row, int col);
int removeValueFromField(int row, int col);
int getValueFromField(int row, int col);
int solve(int row, int col);

#endif /* _SUDOKU_H_ */

sudoku.c

#include "sudoku.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#define SIZE 9
#define SQRT_SIZE 3

int field[SIZE][SIZE];
int initial[SIZE][SIZE];


/* Initializes the sudoku array.
 * The field initial keeps the original start value for
 * figuring out if a value is fixed or can be changed. */
void init(int begin[SIZE][SIZE]) {
    memcpy(field, begin, SIZE * SIZE * sizeof(int));
    memcpy(initial, begin, SIZE * SIZE * sizeof(int));
}

/* really pretty prints the sudoku array */
void print() {
    int row, col;
    // print the first line
    printf("||");
    for (col = 0; col < SIZE - 1; col++) {
        if (col % SQRT_SIZE == SQRT_SIZE - 1)
            printf("===++");
        else
            printf("===+");
    }
    printf("===||\n");
    // loop through all rows of the array
    for (row = 0; row < SIZE; row++) {
        // print the line with field values
        for (col = 0; col < SIZE; col++) {
            if (col % SQRT_SIZE == 0)
                printf("|| ");
            else
                printf("| ");
            if (field[row][col] == 0)
                printf("  ");
            else
                printf("%d ", field[row][col]);
        }
        // print the separation line;
        // depending on the result of the modulo operation
        // print a single or double line
        printf("||\n||");
        if (row % SQRT_SIZE == SQRT_SIZE - 1) {
            for (col = 0; col < SIZE - 1; col++) {
                if (col % SQRT_SIZE == SQRT_SIZE - 1)
                    printf("===++");
                else
                    printf("===+");
            }
            printf("===||\n");
        }
        else {
            for (col = 0; col < SIZE - 1; col++) {
                if (col % SQRT_SIZE == SQRT_SIZE - 1)
                    printf("---++");
                else
                    printf("---+");
            }
            printf("---||\n");
        }
    }
}

/* Checks if the value is valid and can be set into the field.
 * The function returns false if the value is already present or
 * has been one of the initial values. */
int checkValueInField(int value, int row, int col) {
    int i, r, c;
    int squareRow;
    int squareCol;
    // checks for initial values
    if (initial[row][col] != 0) {
        if (initial[row][col] == value)
            return 1;
        else
            return 0;
    }

    // check horizontally
    for (i = 0; i < SIZE; i++) {
        if (field[row][i] == value) return 0;
    }

    // check vertically
    for (i = 0; i < SIZE; i++) {
        if (field[i][col] == value) return 0;
    }

    // check square
    squareRow = row / SQRT_SIZE;
    squareCol = col / SQRT_SIZE;
    for (r = squareRow * SQRT_SIZE; r < squareRow * SQRT_SIZE + SQRT_SIZE; r++) {
        for (c = squareCol * SQRT_SIZE; c < squareCol * SQRT_SIZE + SQRT_SIZE; c++) {
            if (field[r][c] == value) return 0;
        }
    }

    return 1;
}

/* Set a value in the sudoku field if the field is empty.
 * The method returns false if the field contains a fixed number. */
int setValueInField(int value, int row, int col) {
    if (initial[row][col] == 0) {
        field[row][col] = value;
        return 1;
    }
    else if (initial[row][col] == value)
        return 1;
    return 0;
}

/* Removes a value in the sudoku field if it doesn't contain an initial value.
 * The method returns false if the field contains a fixed number and cannot be
 * removed. */
int removeValueFromField(int row, int col) {
    if (initial[row][col] == 0) {
        field[row][col] = 0;
        return 1;
    }
    return 0;
}

/* Returns the value in the field */
int getValueFromField(int row, int col) {
    return field[row][col];
}

/* Return true if you've found a valid solution for the sudoku. Use the
 * return value to abort the backtracking algorithm if you've found the
 * first solution, otherwise you would search for a possible solution. */
int solve(int row, int col) {
    /* Implement a backtracking for solving the sudoku */
    for (int i = 1; i <= 9; i++) {
        if ((checkValueInField(i, row, col)) == 1) {
            setValueInField(i, row, col);
        }
        solve(row, col + 1);
        solve(row + 1, col);
    }
    return 0;
}

main.c

#include <stdio.h>
#include "sudoku.h"

int main(int argc, char * const argv[]) {
    int initial[SIZE][SIZE] = {
        {0, 1, 0, 0, 0, 9, 0, 5, 0},
        {0, 9, 0, 0, 0, 0, 4, 8, 0},
        {0, 6, 0, 1, 0, 4, 0, 0, 0},
        {0, 0, 5, 0, 0, 0, 9, 3, 0},
        {0, 0, 0, 7, 0, 2, 0, 0, 0},
        {0, 2, 1, 0, 0, 0, 8, 0, 0},
        {4, 0, 0, 0, 8, 0, 6, 0, 9},
        {0, 0, 0, 0, 6, 0, 5, 0, 3},
        {2, 0, 0, 0, 3, 0, 0, 0, 0},
    };

    init(initial);
    print();
    solve(0, 0);
    print();

    return 0;
}

You might want to look at what is a backtracking algorithm

Recusively Moving through the grid

Your solve would be solving one position (tracked by row and col ) at a time and recursively check solve the next position.

So your solve function should at least walk through the grid

int solve(int row, int col) {
    // solve next column in the current row
    return solve(row, col + 1);
}

As you can see the issue become that the col would be growing indefinitely without checking other rows. (by the way the first element of an array in C have an index of 0 )

So we need to move to the other row once we reach the end of this one ( Assuming that END_COLUMN_INDEX contains the index of the last column)

   if(col == END_COLUMN_INDEX) { // we just reached the end of the current row
        return solve(row+1, 0); // solve the beginning of the next row
   }

Now your solving will automatically move to the next row, but what about when we reach the last row ( Assuming that END_ROW_INDEX contains the index of the row column)

   if((col == END_COLUMN_INDEX) && (row == END_ROW_INDEX)) { // we reached the end of the grid meaning that we might have successfully solved the whole grid
       return 1; // return true
   }

Now walking throught what should be implemented as this point.

solve(0,0) -> solve(0,1)
solve(0,1) -> solve(0,2)
solve(0,2) -> solve(0,3)
...
solve(0,END_COLUMN_INDEX - 1) -> solve(0, END_COLUMN_INDEX)
solve(0, END_COLUMN_INDEX) -> solve(1, 0)
...
...
solve(END_ROW_INDEX , END_COLUMN_INDEX - 1) -> solve(END_ROW_INDEX , END_COLUMN_INDEX) -> return true
(the true value is returned through each upper level of recursion)

We are now recursively moving through the grid

Solving the Sudoku

for each cell you need to check

  1. if the cell is already filled (you can then solve the next cell)
  2. check a value (1 through 9, using checkValueInField ):
  3. if the found value is ok, you can store the value in the grid ( setValueInField ) and try to solve the next cell
  4. else try the next value
  5. what if we have tried all the value and nothing fits ?
  6. that means that the upper level of recursion is wrong, so the solve function will return false to communicate that the value in the previous cell is wrong ( the upper layer would be at step 1 or 3 )

  7. test what solve -ing the next cell returned ( at step 1 or 3 )

  8. true, means that we solved the next cell and all the following cells
  9. false means that we have a value that made the next cell un- solve able, we might want to try other values (backtracking ).

when returning false to the upper value of recursion you must not forget to restore the value of the current cell to its original value ( removeValueFromField ).

Putting it all together

At this point you should have all the guides to resolve your issue and write your recursive sudoku solving function.

Additionally internet is filled with great example of sudoku solving code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM