-4

I'm making a sudoku generator in C, but when I start the program it goes random in endless loop. Sometimes it prints all the rows, sometimes only one, etc.. etc.. (See images below) This is the code What is the problem?

#include <string.h>
#include <stdlib.h>
#include "sudoku.h"
#include <stdio.h>
#include <time.h>

int dimension = 9;

int main(int argc, char** argv){
  int dimension = 9;
  int j ,k,i ;
  int ** sudo =  malloc(sizeof(*sudo)*dimension);
  for ( j = 0; j< dimension; j++){
    sudo[j] =  malloc(sizeof(int)*dimension);
  }
    riempiSudoku(sudo);
  return 0;

void riempiSudoku(int** sudo){  //fill sudoku
  int j,i,k,f;
  int len; 
  //srand ( time(NULL));
  int ran;
  for (i=0;i<dimension;i++){
    for(j=0;j<dimension;j++){
      if(!thereisNumber(sudo, i,j)){
    printf("\nNon ci sono numeri\n");//no solution, stop the program
    exit(0);
      }
      printf("%d ", sudo[i][j]);
    }
    printf("\n");
  }
}


int checkRow(int** sudo, int row, int value){ //check if the number is in the row
  int i;
  for (i = 0; i<dimension; i++){
    if (sudo[row][i] == value)
      return 1;
  }
  return 0;
}

int checkCol(int** sudo, int col, int value){//check if the number is in the col
  int i;
  for (i = 0; i<dimension; i++){
    if (sudo[i][col] == value)
      return 1;
  }
  return 0;

}


int checkSquare(int** sudo, int row, int col, int value){
  int i, j;
  for(i= (row/3)*3; i<(row/3)*3 +3; i++){
    for(j=(col/3)*3; j<(col/3)*3 +3; j++){
      if(sudo[i][j] == value)
    return 1;
    }
  }
  return 0;

}
int thereisNumber(int** sudo, int i,int j){
  int options[dimension];
  int len;
  for (len=0; len<dimension; len++)
    options[len] = len + 1;             // populate the array with 1..9
  while (len) {
    int ran = rand() % len;         // select an index into the list
    int digit = options[ran];      // get the number from the available list
    if (checkSquare(sudo,i,j,digit) || checkRow(sudo,i,digit) || checkCol(sudo,j,digit))
        options[ran] = options[--len];  // remove digit from list
    else{
      sudo[i][j]= digit;
      return len>0;
    }
  }
  return 0; //thereisNumber(sudo,i,j-1);
}

those are the screenshots https://i.stack.imgur.com/793yb.jpg this is the result of gdb https://i.stack.imgur.com/DGAGo.jpg

Leonardo
  • 499
  • 1
  • 7
  • 18
  • OK, what did you find out when you ran this under your debugger? – Martin James Aug 23 '15 at 14:01
  • I tried with gdb and when it stops i press ctrl+c and every time says something different. Sometimes about some function, sometimes about random.c (file or directory missing). How can I see precisely what causes the endless loop? – Leonardo Aug 23 '15 at 14:05
  • 1
    If you get to a place where there is no solution, then trying random values won't help. You need to back up then. – stark Aug 23 '15 at 14:09
  • You do not have any function prototypes, therefore the compiler cannot check the argument types for error, it can only guess the argument type from the parameters you supply on calling. Oh! Whoa! They are in `"sudoku.h"`? That's why we need MCVE so we don't have to ask stupid questions. – Weather Vane Aug 23 '15 at 14:12
  • `ran = rand() % dimension; while(checkSquare(sudo,i,j,ran + 1) || checkRow(sudo,i,ran + 1) || checkCol(sudo,j,ran + 1));` Can not exit the loop when exists that when there is no possible placement figures. – BLUEPIXY Aug 23 '15 at 14:15
  • @WeatherVane I've got the function prototypes in sudoku.h file and then I use a makefile to compile everything. – Leonardo Aug 23 '15 at 14:15
  • 2
    `stand(time(NULL));` , `stand` --> `srand` ?? – BLUEPIXY Aug 23 '15 at 14:17
  • @BLUEPIXY I'm sorry, i type wrong, in the orignal code there is srand, but I don't really understand your first comment. – Leonardo Aug 23 '15 at 14:20
  • You would be advised not to call `srand()` until you have debugged, then you get a repeatable run. – Weather Vane Aug 23 '15 at 14:20
  • E.g[2 7 9 6 1 3 8 4 5],[1 8 3 5 7 4 6 2 9],[6 4 5 9 8 2 3 1 7],[8 9 4 2 5 7 1 6 3],[7 1 2 8 6 9 4 5 X] X is 3 (by row) but can't put 3(It does not pass the test (So It can not be out of the loop), already exist pre row). – BLUEPIXY Aug 23 '15 at 14:23
  • no other typos , this is what gdb says http://imgur.com/qp8omko – Leonardo Aug 23 '15 at 14:28
  • Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a [mcve] – too honest for this site Aug 23 '15 at 14:30
  • **You** tell what the problem is. We try to help finding the reason for missbehaving. Do not post screenshots and if an information is relevant for the question, please **add** to the question, not in a comment. – too honest for this site Aug 23 '15 at 14:31
  • Comment out the `srand()` calls. Find which line it hangs on. Put `printf` statements when you get to that line. Examine the vars, etc, divide and conquer. – Weather Vane Aug 23 '15 at 14:33
  • The problem is that this program sometimes causes an endless loop, sometimes not. I would like to understand why, because I don't know so I posted my question here hoping that someone could help me. – Leonardo Aug 23 '15 at 14:33
  • 2
    I have advised you twice now, don't call `srand()` so that the run is repeatable. If the default works, hard code a seed until you find one that does not. Then you can examine the code behaviour without shifting sand under your feet. – Weather Vane Aug 23 '15 at 14:34
  • And then, if it still fails in different places, you have problems with uninitialised variables or array over runs, rather than the logic. – Weather Vane Aug 23 '15 at 14:38

1 Answers1

1

Your program reaches a stalemate when there are NO possible solutions - as commented by @BLUEPIXY.

But your program can't detect that, it keeps trying more random numbers. I suggest using something like the Fisher-Yates shuffle used with cards, that removes unsuccessful candidates from the array of possibilities.

int options[dimension];
int len;
for (len=0; len<dimension; len++)
    options[len] = len + 1;             // populate the array with 1..9
while (len) {
    int ran = rand() % len;             // select an index into the list
    int digit = options[ran];           // get the number from the available list
    if (checkSquare(sudo,i,j,digit) || checkRow(sudo,i,digit) || checkCol(sudo,j,digit))
        options[ran] = options[--len];  // remove digit from list
    else break;
}
return len > 0;                         // 0 if failed to find digit

If the function does not succeed, you need to be able to "undo" a history of number placements. That's your next task!

EDIT rather than an "undo" function, at every number placement you could implement the "array of possibilities" that I showed. The solution is rather more complex than you imagined, possibly a recursive solution is what is needed.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • Thank you, with this function the program stops when there isn't any solution. Now I'm trying to implement this "undo" function but it's very hard as you said – Leonardo Aug 23 '15 at 17:15