#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <rlib.h>
#include "rsolve.h"
#define N 9

// VERSION 1



void clear()
{
	printf("\e[2J");
	fflush(stdout);
}
void print_grid(int grid[N][N])
{
	for (int row = 0; row < N; row++)
	{
		for (int col = 0; col < N; col++)
		{
			printf("%d ", grid[row][col]);
		}
		printf("\n");
	}
}


unsigned int solve2(int grid[N][N], unsigned long long *attempts)
{
	(*attempts)++;
	// if(*attempts % 10000000 == 0)
	//           print_grid(grid);
	unsigned int row, col;
	bool emptySpot = false;
	for (row = 0; row < N; row++)
	{
		for (col = 0; col < N; col++)
		{
			if (grid[row][col] == 0)
			{
				emptySpot = true;
				break;
			}
		}
		if (emptySpot)
		{
			break;
		}
	}
	if (!emptySpot)
		return true;
	for (int num = 1; num <= 9; num++)
	{
		if (ris_safe(grid, row, col, num))
		{
			grid[row][col] = num;

			if (solve2(grid, attempts))
			{
				return *attempts;
			}

			grid[row][col] = 0;
		}
	}

	return 0;
}
int solve(int grid[N][N], unsigned long long *steps)
{
	*(steps)++;

	// if(*steps % 1000000){
	//	printf("%lld\n",*steps);
	// }

	int col;
	int row;
	bool found_empty = false;
	for (row = 0; row < N; row++)
	{
		for (col = 0; col < N; col++)
		{
			if (!grid[row][col])
			{
				found_empty = true;
			}
		}
		if (found_empty)
			break;
	}
	if (!found_empty)
		return true;
	for (int i = 1; i < 10; i++)
	{

		if (ris_safe(grid, row, col, i))
		{
			grid[row][col] = i;

			if (solve(grid, steps))
			{
				print_grid(grid);

				return true;
			}
			grid[row][col] = 0;
		}
	}
	return false;
}

int get_next_int(FILE *f)
{
	char c;
	while ((c = getc(f)) && c != EOF)
	{
		if (c < '0' || c > '9')
		{
			continue;
		}
		return c - '0';
	}
	return -1;
}

bool grid_read(int grid[N][N])
{
	for (int row = 0; row < N; row++)
	{
		for (int col = 0; col < N; col++)
		{
			grid[row][col] = get_next_int(stdin);
            clear();
			print_grid(grid);
			if (grid[row][col] == -1)
			{
				return false;
			}
		}
	}
	return true;
} /*
 1 2 3 4 5 6 9 7 8
 4 5 6 7 8 9 1 2 3
 7 8 9 3 2 1 6 4 5
 9 4 7 8 3 2 5 1 6
 2 6 8 9 1 5 7 3 4
 5 3 1 6 7 0 0 0 0
 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 */

/*
0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  9
 0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0
 0  0  2  0  0  0  0  0  0
 0  0  0  0  0  0  0  2  0
 1  0  0  3  0  7  0  0  0
*/
bool is_empty(int grid[N][N])
{
	for (int i = 0; i < N * N; i++)
	{
		if (grid[i / 9][i % 9] != 0)
			return false;
	}
	return true;
}

/* 27 secs with rsolve. Good test:
 2  0  0  0  0  8  0  0  0
 0  0  0  0  0  0  0  9  0
 0  0  8  0  2  0  0  0  5
 0  0  0  0  0  7  0  0  0
 0  4  0  0  0  0  9  0  0
 0  0  0  3  0  5  0  0  0
 0  2  0  0  0  1  0  0  0
 0  9  0  0  0  0  8  0  0
 0  8  0  0  0  2  0  0  0
 */

/*
4:16

7 0 0 0 0 4 0 0 6 
0 0 3 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 4 
4 0 0 0 6 0 0 5 0 
0 0 0 0 4 0 1 0 0 
0 8 0 0 0 0 0 0 9 
0 0 0 0 5 0 0 4 0 
0 0 0 0 2 0 0 6 0 
0 0 0 7 0 0 0 0 0 
*/



int main(int argc, char *argv[])
{
    printf("Usage: ./solve [auto (optional)]\n");
    printf("       run without parameters to provide your own grid. Many formats supported, XML, HTML, JSON, NO DELIMITER, DELMITED BY ANYTHING.\n");
RBENCH(1000000,{
         int * g = rgenerate_puzzle(17);
		 free(g);  
        })
	srand(time(NULL));
	setbuf(stdout, 0);
	int grid[N][N];
	memset(grid, 0, N * N * sizeof(int));
	clear();
	int * ex_grid = rgenerate_puzzle(17);
	printf("Paste grid in this format:\n");
	print_grid(ex_grid);
	// grid[8][8] = 9;
	//	grid[8][8] = 8;
	while (argc != 2)
	{
		if (is_empty(grid))
			while (!grid_read(grid))
			{
				printf("Invalid grid\n");
			}
		if (rvalidate_grid(grid))
		{
			break;
		}
		printf("Corrupt grid..\n");
		memset(grid, 0, N * N * sizeof(int));
	}
	clear();
	int grid_original[N][N];
    if(argc == 2){
        memcpy(grid, ex_grid, N * N * sizeof(int));
    }
	memcpy(grid_original, grid, N * N * sizeof(int));
	printf("Grid valid. Solving...\n\n");
	unsigned long long steps = 0;
	nsecs_t start = nsecs();
	RBENCH(1, {
		memcpy(grid, grid_original, N * N * sizeof(int));
		steps = 0;
		if (rsolve(grid, &steps))
		{
            printf("original:\n");
			print_grid(grid_original);
            printf("\ncompleted:\n");
            print_grid(grid);
			printf("\n");
		}
		
		
	});
    printf("Steps: %u\n", steps);;
		

	RBENCH(1, {
		memcpy(grid, grid_original, N * N * sizeof(int));
		steps = 0;
		if (solve2(grid, &steps)){
			printf("%s","2");
		}
		memcpy(grid, grid_original, N * N * sizeof(int));
	});
	printf("Steps: %u\n", steps);;
		
	nsecs_t end = nsecs();
		
	printf("Duration: %s\n", format_time(end - start));
	return 0;
}