I have an assignment, to create a program that solves 9x9 sudoku puzzle. The specifications are the following:
- Filename must be given to command line as a parameter (EDIT:
argv[0]isn't necessary, just need to input from keyboard withscanffunction) - File must be binary
- All arrays must be dynamically allocated
- Binary file contains numbers that determine the coords and the desired number e.g 367 means 3rd row 6th column and number 7
My program allocates a 2D array dynamically, then allocates space to save the filename, then opens the binary file to read data. Using printf to debug my program it seems that data gets saved to importedData array appropriately and when assigning those data on sudoku puzzle, either the program crashes, or doesn't assign the values properly. Here is my code:
Sudoku.c
#include <stdio.h>
#include <stdlib.h>
#include "sudokulib.h"
#define MALLOC_ERROR 0xFF
#define FILE_NOT_FOUND 0xFFF
int main(int argc,char ** argv)
{
char **matrix;
int i,j;
int row,column,num;
FILE * fp;
char * filename;
char * importedData;
matrix=(char **)malloc(9*sizeof(char *));
if (!matrix)
exit(MALLOC_ERROR);
for (i=0;i<9;++i)
{
matrix[i]=(char *)malloc(9*sizeof(char));
if (!matrix[i])
exit(MALLOC_ERROR);
}
initSudoku(matrix);
printf ("Give me the name of data file: ");
filename=(char *)malloc(100*sizeof(char));
if (!filename)
exit(MALLOC_ERROR);
scanf("%s",filename);
fp=fopen(filename,"rb");
if (!fp)
{
printf ("File not found\n");
exit(FILE_NOT_FOUND);
}
importedData=(char *)malloc(sizeof(char)*81*3);
if (!importedData)
exit (MALLOC_ERROR);
fread(importedData,1,243,fp);
i=0;
while (importedData[i] != ' ' && importedData[i+1] != ' ' && importedData[i+2] != ' ' && importedData[i] >= '1' && importedData[i+1] >= '1' && importedData[i+2] >= '1' && importedData[i] <= '9' && importedData[i+1] <= '9' && importedData[i+2] <= '9')
{
row=importedData[i] - 48; /* Convert from ascii code to number */
column=importedData[i+1] - 48;
num=importedData[i+2] - 48;
matrix[row][column]=num;
i=i+3;
}
printf("Sudoku after importing data:\n\n");
printSudoku(matrix);
system("pause");
if (solvePuzzle(matrix))
{
printSudoku(matrix);
}
else
printf ("Puzzle has no solution\n");
fclose(fp);
free(filename);
for (i=0;i<9;++i)
{
free(matrix[i]);
}
free(matrix);
return 0;
}
Sudokulib.h
#include <stdlib.h>
#include <stdio.h>
/* Function Prototypes Begin Here */
void printSudoku(char **);
void initSudoku(char **);
int checkRow(char **,int,int);
int checkCol(char **,int,int);
int check3x3(char **,int,int,int);
int checkIfEmpty(char **,int*,int*);
int solvePuzzle (char **);
/* Function Prototypes End Here */
void printSudoku(char ** Mat)
{
int i,j;
for (i=0;i<9;++i)
{
printf ("-------------------\n");
printf("|");
for (j=0;j<9;++j)
{
printf("%d|",Mat[i][j]);
}
printf("\n");
}
printf ("-------------------\n");
}
void initSudoku(char ** Mat)
{
int i,j;
for (i=0;i<9;++i)
for (j=0;j<9;++j)
Mat[i][j]=0;
}
int checkRow (char ** Mat,int row, int num) // if row is free returns 1 else returns 0
{
int col;
for (col = 0; col < 9; col++)
{
if (Mat[row][col] == num-48)
return 0;
}
return 1;
}
int checkCol (char ** Mat,int col , int num) // if column is free returns 1 else returns 0
{
int row;
for (row = 0; row < 9; row++)
{
if (Mat[row][col] == num-48)
return 0;
}
return 1;
}
int check3x3 (char ** Mat, int row, int col, int num) // if number doesnt exist in the 3x3 grid returns 1 else returns 0
{
row = (row/3) * 3; // set to first row in the grid
col = (col/3) * 3; // set to first col in the grid
int i;
int j;
for (i = 0; i < 3; i++) // grid is 3x3
{
for (j = 0; j < 3; j++)
{
if (Mat[row+i][col+j] == num-48)
return 0;
}
}
return 1;
}
int checkIfEmpty(char ** Mat, int *row, int *col) // if a block of the entire puzzle is empty returns 1 else returns 0 also saves the target row and column it found empty
{
for (*row = 0; *row < 9; *row++)
{
for (*col = 0; *col < 9; *col++)
{
if (Mat[*row][*col] == 0)
return 1;
}
}
return 0;
}
int solvePuzzle (char ** Mat)
{
int num;
int row;
int col;
row = 0;
col = 0;
if (!checkIfEmpty(Mat,&row,&col)) // if puzzle is solved return 1
return 1;
for (num = 1; num < 9; num++)
{
if (checkRow (Mat,row,num) && checkCol (Mat,col,num) && check3x3 (Mat,row,col,num))
{
Mat[row][col] = num-48;
}
if (solvePuzzle (Mat))
{
return 1;
}
Mat[row][col] = 0;
}
return 0;
}
Any help to resolve the aforementioned issue is appreciated.
Also keep in mind that int solvePuzzle() is not quite finished and any suggestions to improve this function are welcome.
EDIT: Here are the contents of binary file data2.bin that causes wrong assignment
142156177191216228257289311329364375418422441484534546562579625663682698739743787794824855883896
Output:
Give me the name of data file: data2.bin
Sudoku after importing data:
-------------------
|0|0|0|0|0|0|0|0|0|
-------------------
|0|0|0|0|2|6|0|7|0|
-------------------
|0|6|8|0|0|7|0|0|9|
-------------------
|0|1|9|0|0|0|4|5|0|
-------------------
|0|8|2|0|1|0|0|0|4|
-------------------
|0|0|0|4|6|0|2|9|0|
-------------------
|0|0|5|0|0|0|3|0|2|
-------------------
|0|0|0|9|3|0|0|0|7|
-------------------
|0|0|4|0|0|5|0|0|3|
-------------------
Press any key to continue . . .
EDIT 2: Found out that if a very small binary file is used that contains very few data e.g. 123245321 works fine, but if data exceed 9 bytes, then the puzzle gets messed up.