// Basado en el ejercicio 2 del Examen de IO de enero 1999
#include <stdio.h>

#define FILE_NAME	"t7_puzzle.txt"

#define MAX	4

#define NORTE	'n'
#define SUR	's'
#define ESTE	'e'
#define OESTE	'o'

#define TRUE	1
#define FALSE	0

typedef struct {
	int n;
} t_casilla;

typedef struct {
	int mida;
	t_casilla cas[MAX][MAX];
	int f; /* fila del cuadrado vacío */
	int c; /* columna del cuadrado vacío */
} t_tablero;

void imprimir_casilla(t_casilla cas) {
	if (cas.n == 0) {
		printf(" ");
	} else {
		if (cas.n < 10) {
			printf("%c", cas.n+'0');
		} else {
			printf("%c", cas.n-10+'A');
		}
	}
}

void imprimir_tablero(t_tablero t) {
	int f, c;

	for(f=0;f<t.mida;f++) {
		for(c=0;c<t.mida;c++) {
			imprimir_casilla(t.cas[f][c]);
		}
		printf("\n");
	}
	printf("\n");
}

int leer_casilla(FILE *fp, t_casilla *p_cas) {
	char c;

	fscanf(fp, "%c", &c);
	if (c>='A' && c<='F') {
		p_cas->n = c-'A'+10;
	} else {
		p_cas->n = c-'0';
	}

	return p_cas->n;
}

int leer_numero(FILE *fp) {
	int n;

	fscanf(fp, "%d", &n);

	return n;
}

char leer_caracter(FILE *fp) {
	char c;

	fscanf(fp, "%c", &c);

	return c;
}

void leer_tablero(t_tablero *p_t) {
	FILE *fp;
	int f, c;

	fp=fopen(FILE_NAME, "r");
	p_t->mida = leer_numero(fp);
	leer_caracter(fp);
	for(f=0;f<p_t->mida;f++) {
		for(c=0;c<p_t->mida;c++) {
			if (leer_casilla(fp, &p_t->cas[f][c]) == 0) {
				p_t->f = f;
				p_t->c = c;
			}
		}
		leer_caracter(fp);
	}
	fclose(fp);
}

int esta_tablero_resulto(t_tablero t) {
	int f, c, n, mida = t.mida;

	for(n=1, f=0;f < mida; f++) {
		for(c=0;c < mida; c++, n++) {
			if (t.cas[f][c].n != n && n != mida*mida) {
				return FALSE;
			}
		}
	}

	return TRUE;
}

void movimiento_incorrecto() {
	printf("Movimiento incorrecto\n");
}

void mueve_vacio(t_tablero *p_t, int f1, int c1, int f2, int c2) {
	int aux;

	aux = p_t->cas[f1][c1].n;
	p_t->cas[f1][c1].n = p_t->cas[f2][c2].n;
	p_t->cas[f2][c2].n = aux;

	p_t->f = f2;
	p_t->c = c2;
}

void jugar(t_tablero *p_t){
	char c;
	int tf = p_t->f, tc = p_t->c;

	printf("Siguiente movimiento [n/s/e/o]: ");
	scanf("\n%c", &c);

	switch (c) {
		case NORTE:
			if (tf>0) {
				mueve_vacio(p_t, tf, tc, tf-1, tc);
			} else {
				movimiento_incorrecto();
			}
			break;
		case SUR:
			if (tf<(p_t->mida-1)) {
				mueve_vacio(p_t, tf, tc, tf+1, tc);
			} else {
				movimiento_incorrecto();
			}
			break;
		case OESTE:
			if (tc>0) {
				mueve_vacio(p_t, tf, tc, tf, tc-1);
			} else {
				movimiento_incorrecto();
			}
			break;
		case ESTE:
			if (tc<(p_t->mida-1)) {
				mueve_vacio(p_t, tf, tc, tf, tc+1);
			} else {
				movimiento_incorrecto();
			}
			break;
	}
}

void imprimir_instruciones() {
	printf("Mueve la casilla vacia hasta tener las casillas ordenadas por numero.\nSolucion en un tablero 4x4:\n1234\n5678\n9ABC\nDEF \n\nPosicion inicial:\n");
}

int main() {
	t_tablero t;

	leer_tablero(&t);
	imprimir_instruciones();
	imprimir_tablero(t);
	while(!esta_tablero_resulto(t)) {
		jugar(&t);
		imprimir_tablero(t);
	}

	return 0;
}

