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

#define SIZE 9
#define SOZE 3

struct score {
    char player[20];
    int lives;
};

void printBoard(int grid[][SIZE]);
void playGame(int level);
int isValidMove(int grid[][SIZE], int row, int col, int num);
int isBoardFull(int grid[][SIZE]);
int solveSudoku(int grid[][SIZE]);
int nextround(int grid[][SIZE]);
void check(int grid[][SIZE], int row, int col);
void sudoku(int grid[][SIZE]);
void saveScore(struct score player);
void displayHighscores();
void solveSudokuPuzzle(int grid[][SIZE]);
void copyGrid(int grid[][SIZE], int copyGrid[][SIZE]);

void printBoard(int grid[][SIZE]) {
    int i, j;
    printf("\n  Tablero  Sudoku\n");
    printf("  ---------------------\n");
    for (i = 0; i < SIZE; i++) {
        printf("  ");
        for (j = 0; j < SIZE; j++) {
            if (j % SOZE == 0 && j != 0) {
                printf("| ");
            }
            if (grid[i][j] == 0) {
                printf("- ");
            } else {
                printf("%d ", grid[i][j]);
            }
        }
        printf("\n");
        if ((i + 1) % SOZE == 0 && i != SIZE - 1) {
            printf("  ------|-------|------\n");
        }
    }
    printf("  ---------------------\n");
}

void playGame(int level) {
    int grid[SIZE][SIZE];
    int i, j;

    // Inicializar grilla con ceros
    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            grid[i][j] = 0;
        }
    }

    // Asignar valores al azar a algunas llamadas basaads en nivel seleccionado
    int filledCells;
    if (level == 1) {
        filledCells = 30;
    } else if (level == 2) {
        filledCells = 20;
    } else if (level == 3) {
        filledCells = 10;
    }

    srand(time(NULL));
    int count = 0;
    while (count < filledCells) {
        int row = rand() % SIZE;
        int col = rand() % SIZE;
        int num = rand() % SIZE + 1;
        if (grid[row][col] == 0 && isValidMove(grid, row, col, num)) {
            grid[row][col] = num;
            count++;
        }
    }

    printBoard(grid);
    sudoku(grid);
}

int isValidMove(int grid[][SIZE], int row, int col, int num) {
    int i, j;
    // Revisa si el numero ya existe en alguna fila o columna
    for (i = 0; i < SIZE; i++) {
        if (grid[row][i] == num || grid[i][col] == num) {
            return 0;
        }
    }

    // Revisa si el numero ya existe en la misma caja 3x3
    int startRow = row - row % SOZE;
    int startCol = col - col % SOZE;
    for (i = 0; i < SOZE; i++) {
        for (j = 0; j < SOZE; j++) {
            if (grid[startRow + i][startCol + j] == num) {
                return 0;
            }
        }
    }

    return 1;
}

int isBoardFull(int grid[][SIZE]) {
    int row, col;
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            if (grid[row][col] == 0) {
                return 0; // Aun hay llamadas vacias
            }
        }
    }
    return 1; // Todas las casillas estan llenas
}

int solveSudoku(int grid[][SIZE]) {
    int row, col, num;
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            if (grid[row][col] == 0) {
                for (num = 1; num <= SIZE; num++) {
                    if (isValidMove(grid, row, col, num)) {
                        grid[row][col] = num;
                        if (solveSudoku(grid)) {
                            return 1;
                        }
                        grid[row][col] = 0;
                    }
                }
                return 0;
            }
        }
    }

    return 1;
}

int nextround(int grid[][SIZE]) {
    int row, col;
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            if (grid[row][col] == 0) {
                return 1; // Aun hay celdas vacias
            }
        }
    }
    return 0; // Todas las celdas estan completas
}

void check(int grid[][SIZE], int row, int col) {
    int solution = 0;
    int num;

    printf("\nIngresa el numero: ");
    scanf("%d", &num);

    if (isValidMove(grid, row, col, num)) {
        grid[row][col] = num;
        printf("\nMovida Valida!\n");
        printBoard(grid);
        solution = solveSudoku(grid);
        if (solution && !nextround(grid)) {
            printf("\nFelicitaciones! Resolviste el Sudoku!\n");
        } else {
            printf("\nContinua resolviendo...\n");
        }
    } else {
        printf("\nMovida Invalida! Intenta de nuevo.\n");
    }
}

void sudoku(int grid[][SIZE]) {
    int row, col;
    printf("\nEmpeza a resolver el Sodoku!\n");
    while (nextround(grid)) {
        printf("\nIngresa la fila (0-8) y la columna (0-8) a revisar: ");
        scanf("%d %d", &row, &col);
        if (row >= 0 && row < SIZE && col >= 0 && col < SIZE) {
            if (grid[row][col] == 0) {
                check(grid, row, col);
            } else {
                printf("\nLa celda ya esta llena. Proba con otra.\n");
            }
        } else {
            printf("\nEntrada Invalida! Intenta de nuevo.\n");
        }
    }
}

void saveScore(struct score player) {
    FILE *file = fopen(".puntajes_sodoku.txt", "a");
    if (file != NULL) {
        fprintf(file, "%s %d\n", player.player, player.lives);
        fclose(file);
    }
}

void displayHighscores() {
    printf("\n    Puntajes\n");
    printf("  -----------------\n");
    FILE *file = fopen(".puntajes_sodoku.txt", "r");
    if (file != NULL) {
        char name[20];
        int lives;
        while (fscanf(file, "%s %d", name, &lives) != EOF) {
            printf("  %-15s %d\n", name, lives);
        }
        fclose(file);
    }
    printf("  -----------------\n");
}

void solveSudokuPuzzle(int grid[][SIZE]) {
    if (solveSudoku(grid)) {
        printf("\nSolucion encontrada!\n");
        printBoard(grid);
    } else {
        printf("\nNo existe solucion al puzzle Sodoku dado.\n");
    }
}

void copyGrid(int grid[][SIZE], int copyGrid[][SIZE]) {
    int row, col;
    for (row = 0; row < SIZE; row++) {
        for (col = 0; col < SIZE; col++) {
            copyGrid[row][col] = grid[row][col];
        }
    }
}

int main() {
    int choice, level;
    struct score player;

    printf("\nBienvenido al Sodoku!\n");

    do {
        printf("\nMenu:\n");
        printf("1. Jugar una Pardida\n");
        printf("2. Mostrar los Puntajes\n");
        printf("3. Resolver un Puzzle Sudoku\n");
        printf("4. Salir\n");
        printf("Ingresa tu seleccion (1-4): ");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                printf("\nSelecciona el Nivel de Dificultad:\n");
                printf("1. Facil\n");
                printf("2. Medio\n");
                printf("3. Dificil\n");
                printf("Ingresa tu eleccion (1-3): ");
                scanf("%d", &level);
                playGame(level);
                break;
            case 2:
                displayHighscores();
                break;
            case 3: {
                int grid[SIZE][SIZE];
                printf("\nIngresa el puzzle Sodoku (usa 0 para celdas vacias):\n");
                for (int i = 0; i < SIZE; i++) {
                    for (int j = 0; j < SIZE; j++) {
                        printf("Ingresa el numero de fila %d, columna %d: ", i, j);
                        scanf("%d", &grid[i][j]);
                    }
                }
                printf("\nResolviendo Sodoku...\n");
                solveSudokuPuzzle(grid);
                break;
            }
            case 4:
                printf("\nGracias por jugar Sodoku! Adios!\n");
                break;
            default:
                printf("\nOpcion Invalida! Intenta de nuevo.\n");
        }

    } while (choice != 4);

    return 0;
}