// code by Salvatore Cerruto
// this code allow to solve sudoku with recursive approach

/* sudolib.h */

typedef enum{FALSE, TRUE} boolean;

FILE *aggancio_file(char nomefile[]);
int get_matrix(FILE *file, int ***matrice, char nomefile[]);
int genera_soluzione(int **matrice, int N, int riga, int colonna);
void stampa_soluzione(int **matrice, int N);
int controlla_sudoku(int **matrice, int N, int riga, int colonna);

/* sudolib.c */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "sudolib.h"

FILE *aggancio_file(char nomefile[])
{
    FILE *file=NULL;

    file=fopen(nomefile, "r");
    return (file);
}

int get_matrix(FILE *file, int ***matrice, char nomefile[])
{
    int temp, item=0, riga, colonna;

    while(fscanf(file, "%d", &temp)!=EOF)
        item++;
    fclose(file);
    file=aggancio_file(nomefile);
    if(file!=NULL)
        {
            /** allocazione righe **/

            *matrice=(int **) malloc(sqrt(item)*sizeof(int *));
            for(riga=0; riga<sqrt(item); riga++)
                {
                    /** allocazione colonne e scansione file **/

                    (*matrice)[riga]=(int *) malloc(sqrt(item)*sizeof(int));
                    for(colonna=0; colonna<sqrt(item); colonna++)
                        fscanf(file, "%d", &(*matrice)[riga][colonna]);
                }
        }
    /** restituisco la dimensione della matrice **/

    return (sqrt(item));
}

int controlla_sudoku(int **matrice, int N, int riga, int colonna)
{
    /** is e js sono gli indici usati per evidenziare le sottomatrici **/

    int i, j, is, js, k=floor(sqrt(N));

    /** controllo che non ci siano elementi uguali sulla colonna **/

    for(i=0; i<N; i++)
        if((matrice[i][colonna]==matrice[riga][colonna])&&(i!=riga))
            return 0;

    /** controllo che non ci siano elementi uguali sulla riga **/

    for(j=0; j<N; j++)
        if((matrice[riga][j]==matrice[riga][colonna])&&(j!=colonna))
            return 0;

    /** controllo della sottomatrice corrente **/

    is=(riga/k)*k;
    js=(colonna/k)*k;
    for(i=is; i<is+k; i++)
        for(j=js; j<js+k; j++)
            {
                if((matrice[i][j]==matrice[riga][colonna])&&(i!=riga||j!=colonna))
                    return 0;
            }
    return 1;
}

int genera_soluzione(int **matrice, int N, int riga, int colonna)
{
    int k;

    if(riga>=N)
        return 1;

    /* se la casella Ã¨ giÃ  presente deve saltarla */

    if(matrice[riga][colonna]!=0)
        {
            if(colonna==N-1)
                return genera_soluzione(matrice, N, riga+1, 0);
            else
                return genera_soluzione(matrice, N, riga, colonna+1);
        }
    for(k=1; k<=N; k++)
        {
            matrice[riga][colonna]=k;
            /**system("cls");
            stampa_soluzione(matrice, N);**/
            if(controlla_sudoku(matrice, N, riga, colonna))
                {
                    if(colonna==N-1)
                        {
                            if(genera_soluzione(matrice, N, riga+1, 0))
                                return 1;
                        }
                    else
                        {
                            if(genera_soluzione(matrice, N, riga, colonna+1))
                                return 1;
                        }
                }
            matrice[riga][colonna]=0;
        }
    return 0;
}

void stampa_soluzione(int **matrice, int N)
{
    int i, j, k, cont_c=0, cont_r=0;

    printf("+");
    for(i=0; i<2*N+sqrt(N)-1; i++)
        printf("-");
    printf("+");
    for(i=0; i<N; i++)
        {
            printf("\n|");
            for(j=0; j<N; j++)
                {
                    printf("%d ", matrice[i][j]);
                    cont_c++;
                    if(cont_c==sqrt(N)&&i!=N)
                        {
                            printf("|");
                            cont_c=0;
                        }
                }
            cont_r++;
            if(cont_r==sqrt(N))
                {
                    printf("\n+");
                    for(k=0; k<2*N+sqrt(N)-1; k++)
                        printf("-");
                    printf("+");
                    cont_r=0;
                }
        }
    printf("\n");
    return;
}

/* main.c */

#include <stdio.h>
#include <stdlib.h>
#include "sudolib.h"
#define MAX 20

int main()
{
    int **matrice, N;
    char nomefile[MAX];
    FILE *filein;

    printf("***** Sudoku *****\n");
    printf("Inserire il nome del file schema: ");
    scanf("%s", nomefile);
    filein=aggancio_file(nomefile);
    if(filein!=NULL)
        {
            N=get_matrix(filein, &matrice, nomefile);
            if(genera_soluzione(matrice, N, 0, 0))
                {
                    printf("\n***** Soluzione *****\n");
                    stampa_soluzione(matrice, N);
                }
            else
                printf("\nSoluzione impossibile");
        }
    return 0;
}

/* example file */

6 0 0 0 0 0 4 3 0
0 0 0 0 7 0 5 1 0
0 0 0 3 0 4 0 0 9
0 0 3 0 0 8 9 0 0
0 2 0 0 0 0 0 8 0
0 0 8 5 0 0 2 0 0
2 0 0 4 0 7 0 0 0
0 1 4 0 6 0 0 0 0
0 6 9 0 0 0 0 0 7