/*
 *      rules.c
 *              - implementace pravidel
 *
 */

#define abs(x) (x>0 ? x : -x)
#define min(a,b) (a<b ? a : b)
#define max(a,b) (a>b ? a : b)

#include <stdio.h>
#include "data.h"

int TahFigurou2(TTah, THra *);

int a1b1(char *c)
{
	if (c[0] >= 'a' && c[0] <= 'h' && c[2] >= 'a' && c[2] <= 'h'
	    && c[1] >= '1' && c[1] <= '8' && c[3] >= '1' && c[3] <= '8')
		return 1;
	else
		return 0;
}

int PreJTT(char *c, THra * H)
{
	int f;
	TTah tah;
	Not2Num(&c[0], &tah.odkud);
	Not2Num(&c[2], &tah.kam);
	f = H->sachovnice[tah.odkud.x][tah.odkud.y];
	/* stoji tam figura? */
	if (f == PPOL) {
		printf("Illegal move (nothing to move): ");
		return 0;
	}
	/* stoji tam figura stejne barvy? */
	switch (H->natahu) {
	case BILYH:
		if (CernaFigura(f)) {
			printf("Illegal move (not your figure): ");
			return 0;
		}
		break;
	case CERNYH:
		if (BilaFigura(f)) {
			printf("Illegal move (not your figure): ");
			return 0;
		}
		break;
	}
	/* lze tou figurou takto tahnout? */
	if (!TahFigurou(tah, H)) {
		printf("Illegal move (ambiguous move): ");
		return 0;
	}
	/* volna cesta ? */
	if ((f == BDAM || f == CDAM || f == BVEZ || f == CVEZ || f == BSTR || f == CSTR)
	    && !(VolnaCesta(tah, H->sachovnice))) {
		printf("Illegal move (occupied way): ");
		return 0;
	}
	return 1;
}

int JeToTah(char *c, THra * H, int vv)
{				/* zda je tah podle pravidel */
	TPozice odkud, kam;
	int f;
	TTah tah;
	static THra hkop;
	Not2Num(&c[0], &odkud);
	Not2Num(&c[2], &kam);
	tah.odkud = odkud;
	tah.kam = kam;
	/* kam ... neni tam figura stejne barvy? */
	f = H->sachovnice[kam.x][kam.y];
	if (f!=PPOL) switch (H->natahu) {
	case BILYH:
		if (BilaFigura(f)) {
			vv && printf("Illegal move (can't take own figure): ");
			return 0;
		}
		break;
	case CERNYH:
		if (CernaFigura(f)) {
			vv && printf("Illegal move (can't take own figure): ");
			return 0;
		}
		break;
	}
	/* lze tou figurou takto tahnout? volne cesty jsou v PreJTT() */
	f = H->sachovnice[odkud.x][odkud.y];
	if ((f == BKRA || f == CKRA || f == BPES || f == CPES) &&
	    !TahFigurou2(tah, H)) {
		vv && printf("Illegal move (ambiguous move): ");
		return 0;
	}
	/* nebudu pak v sachu? */
	/* proved v kopii hry a pokud pak nebude v sachu, tak
	   tu kopii zkopni do originalu ... jinak exit */
	hkop = *H;
	ZpracujTah(c, &hkop);
	/* printf(" ... test sachu ...\n"); */
	if (JeVSachu(H->natahu, &hkop)) {
		vv && printf("Illegal move (moving into check): ");
		return 0;
	}
	/* vse je tedy ok */
	return (1);
}

int BilaFigura(int f)
{
	if (f == BPES || f == BDAM || f == BKRA || f == BVEZ || f == BJEZ || f == BSTR)
		return 1;
	else
		return 0;
}

int CernaFigura(int f)
{
	if (f == CPES || f == CDAM || f == CKRA || f == CVEZ || f == CJEZ || f == CSTR)
		return 1;
	else
		return 0;
}

int TahFigurou2(TTah tah, THra * H)
{
	TFigura fig;
	int dx, dy;
	static THra TH;
	/* nastav fig */
	fig.fig = H->sachovnice[tah.odkud.x][tah.odkud.y];
	fig.pos.x = tah.odkud.x;
	fig.pos.y = tah.odkud.y;
	/* jestli je to pesec, tak zavolej specialni proceduru pro pesce, jinou figuru rovnou testni */
	dx = (int) (tah.kam.x - tah.odkud.x);
	dy = (int) (tah.kam.y - tah.odkud.y);
	switch (fig.fig) {
	case BPES:
	case CPES:
		if ((TahPescem(tah, H)))
			return 1;
		break;
	case BKRA:
		if ((abs(dx) <= 1) && dy <= 1)
			return 1;
		else if ((dx == 2) && (dy == 0) && (H->bily.rochada[0]) &&
			 (H->sachovnice[5][0] == PPOL) &&
			 (H->sachovnice[6][0] == PPOL) &&	/* mala rochada */
			 !JeVSachu(BILYH, H)) {
			TH = *H;
			ZpracujTah("e1f1", &TH);
			if (JeVSachu(BILYH, &TH))
				return 0;
			else
				return 1;
		} else if ((dx == -2) && (dy == 0) && (H->bily.rochada[1]) &&
			   (H->sachovnice[3][0] == PPOL) &&
			   (H->sachovnice[2][0] == PPOL) &&	/* velka rochada */
			   (H->sachovnice[1][0] == PPOL) &&
			   !JeVSachu(BILYH, H)) {
			TH = *H;
			ZpracujTah("e1d1", &TH);
			if (JeVSachu(BILYH, &TH))
				return 0;
			else
				return 1;
		}
		break;
	case CKRA:
		if ((abs(dx) <= 1) && dy <= 1)
			return 1;
		else if ((dx == 2) && (dy == 0) && (H->cerny.rochada[0]) &&
			 (H->sachovnice[5][7] == PPOL) &&
			 (H->sachovnice[6][7] == PPOL) &&	/* mala rochada */
			 !JeVSachu(CERNYH, H)) {
			TH = *H;
			ZpracujTah("e8f8", &TH);
			if (JeVSachu(CERNYH, &TH))
				return 0;
			else
				return 1;
		} else if ((dx == -2) && (dy == 0) && (H->cerny.rochada[1]) &&
			   (H->sachovnice[3][7] == PPOL) &&
			   (H->sachovnice[2][7] == PPOL) &&	/* velka rochada */
			   (H->sachovnice[1][7] == PPOL) &&
			   !JeVSachu(CERNYH, H)) {
			TH = *H;
			ZpracujTah("e8d8", &TH);
			if (JeVSachu(CERNYH, &TH))
				return 0;
			else
				return 1;
		}
		break;
	}
	return 0;
}

int TahFigurou(TTah tah, THra * H)
{
	TFigura fig;
	int dx, dy;
	static THra TH;
	/* nastav fig */
	fig.fig = H->sachovnice[tah.odkud.x][tah.odkud.y];
	fig.pos.x = tah.odkud.x;
	fig.pos.y = tah.odkud.y;
	/* jestli je to pesec, tak zavolej specialni proceduru pro pesce, jinou figuru rovnou testni */
	dx = tah.kam.x - tah.odkud.x;
	dy = tah.kam.y - tah.odkud.y;
	switch (fig.fig) {
	case BPES:
	case CPES:
		if ((TahPescem(tah, H)))
			return 1;
		break;
	case BKRA:
		if ((abs(dx) <= 1) && dy <= 1)
			return 1;
		else if ((dx == 2) && (dy == 0) && (H->bily.rochada[0]) &&
			 (H->sachovnice[5][0] == PPOL) &&
			 (H->sachovnice[6][0] == PPOL) &&	/* mala rochada */
			 !JeVSachu(BILYH, H)) {
			TH = *H;
			ZpracujTah("e1f1", &TH);
			if (JeVSachu(BILYH, &TH))
				return 0;
			else
				return 1;
		} else if ((dx == -2) && (dy == 0) && (H->bily.rochada[1]) &&
			   (H->sachovnice[3][0] == PPOL) &&
			   (H->sachovnice[2][0] == PPOL) &&	/* velka rochada */
			   (H->sachovnice[1][0] == PPOL) &&
			   !JeVSachu(BILYH, H)) {
			TH = *H;
			ZpracujTah("e1d1", &TH);
			if (JeVSachu(BILYH, &TH))
				return 0;
			else
				return 1;
		}
		break;
	case CKRA:
		if ((abs(dx) <= 1) && dy <= 1)
			return 1;
		else if ((dx == 2) && (dy == 0) && (H->cerny.rochada[0]) &&
			 (H->sachovnice[5][7] == PPOL) &&
			 (H->sachovnice[6][7] == PPOL) &&	/* mala rochada */
			 !JeVSachu(CERNYH, H)) {
			TH = *H;
			ZpracujTah("e8f8", &TH);
			if (JeVSachu(CERNYH, &TH))
				return 0;
			else
				return 1;
		} else if ((dx == -2) && (dy == 0) && (H->cerny.rochada[1]) &&
			   (H->sachovnice[3][7] == PPOL) &&
			   (H->sachovnice[2][7] == PPOL) &&	/* velka rochada */
			   (H->sachovnice[1][7] == PPOL) &&
			   !JeVSachu(CERNYH, H)) {
			TH = *H;
			ZpracujTah("e8d8", &TH);
			if (JeVSachu(CERNYH, &TH))
				return 0;
			else
				return 1;
		}
		break;
	case BJEZ:
	case CJEZ:
		if ((abs(dx) == 2) && (abs(dy) == 1))
			return 1;
		else if ((abs(dx) == 1) && (abs(dy) == 2))
			return 1;
		break;
	case BSTR:
	case CSTR:
	case BDAM:
	case CDAM:
		if (((abs(dx) == abs(dy)) || (dy * dx == 0))
		/* && VolnaCesta(tah, H->sachovnice) */ )
			return 1;
		break;
	case BVEZ:
	case CVEZ:
		if (((dx == 0) || (dy == 0))
		/* && VolnaCesta(tah, H->sachovnice) */ )
			return 1;
		break;
	}
	return 0;
}

int TahPescem(TTah tah, THra * H)
{				/* zda je tah podle pravidel */
	int dx, dy;
	dx = tah.kam.x - tah.odkud.x;
	dy = tah.kam.y - tah.odkud.y;
	switch (H->natahu) {
	case BILYH:
		if (dx == 0) {	/* tah dopredu */
			if ((dy == 2) && (tah.odkud.y == 1) &&
			    (H->sachovnice[tah.odkud.x][2] == PPOL) &&
			 (H->sachovnice[tah.odkud.x][tah.kam.y] == PPOL))
				return 1;
			else if ((dy == 1) &&
			 (H->sachovnice[tah.odkud.x][tah.kam.y] == PPOL))
				return 1;
		}		/* tah sikmo */
		if (((dy * abs(dx)) == 1) &&
		    H->sachovnice[tah.kam.x][tah.kam.y] != PPOL)
			return 1;
		else if ((tah.kam.x == H->enpas) && (tah.kam.y == 5) &&
			 ((dy * abs(dx)) == 1) &&
			 H->sachovnice[tah.kam.x][tah.kam.y] == PPOL)
			return 1;
		break;
	case CERNYH:
		if (dx == 0) {	/* taj dopredu */
			if ((dy == -2) && (tah.odkud.y == 6) &&
			    (H->sachovnice[tah.odkud.x][5] == PPOL) &&
			 (H->sachovnice[tah.odkud.x][tah.kam.y] == PPOL))
				return 1;
			else if ((dy == -1) &&
			 (H->sachovnice[tah.odkud.x][tah.kam.y] == PPOL))
				return 1;
		}		/* tah sikmo */
		if (((dy * abs(dx)) == -1) &&
		    H->sachovnice[tah.kam.x][tah.kam.y] != PPOL)
			return 1;
		else if ((tah.kam.x == H->enpas) && (tah.kam.y == 2) &&
			 ((dy * abs(dx)) == -1) &&
			 H->sachovnice[tah.kam.x][tah.kam.y] == PPOL)
			return 1;
		break;
	}
	return 0;
}

int VolnaCesta(TTah tah, TSachovnice sach)
{
	int i, j, odx, dox, ody, doy, sx, sy;
	odx = tah.odkud.x;
	dox = tah.kam.x;
	ody = tah.odkud.y;
	doy = tah.kam.y;
	sx = (int) (dox - odx);
	if (sx != 0)
		sx = sx / abs(sx);
	sy = (int) (doy - ody);
	if (sy != 0)
		sy = sy / abs(sy);
	i = odx + sx;
	j = ody + sy;
	if ((sx >= 0) && (sy >= 0))
		while ((i <= (dox - sx)) && (j <= (doy - sy)) && (i >= 0) && (j >= 0)) {
			if (sach[i][j] != PPOL)
				return 0;
			i += sx;
			j += sy;
	} else if ((sx >= 0) && (sy < 0))
		while ((i <= (dox - sx)) && (j >= (doy - sy)) && (i >= 0) && (j >= 0)) {
			if (sach[i][j] != PPOL)
				return 0;
			i += sx;
			j += sy;
	} else if ((sx < 0) && (sy >= 0))
		while ((i >= (dox - sx)) && (j <= (doy - sy)) && (i >= 0) && (j >= 0)) {
			if (sach[i][j] != PPOL)
				return 0;
			i += sx;
			j += sy;
	} else if ((sx < 0) && (sy < 0))
		while ((i >= (dox - sx)) && (j >= (doy - sy)) && (i >= 0) && (j >= 0)) {
			if (sach[i][j] != PPOL)
				return 0;
			i += sx;
			j += sy;
		}
	return 1;
}

int NajdiFiguru(TPozice p, TSachovnice s, THrac * h, int *fi)
/* dostane pozici a najde figuru v THrac (fi) */
{
	int i = 0, fig;
	/* TFigura      *f2; */
	fig = s[p.x][p.y];
	while (i <= 15 && !((fig == (h->figury[i].fig)) &&
			    (p.x == h->figury[i].pos.x) &&
			    (p.y == h->figury[i].pos.y)))
		i++;
	if (i > 15)
		return 0;
	else
		*fi = i;
	return 1;
}

void OdeberFiguru(THrac * H)
{
	int i = 0;
	while (i <= 15 && (H->figury[i].fig != PPOL))
		i++;
	if (i > 15) {
		printf("DEBUG: Neni zadna odebirana figura :( -> BUG\n");
		return;
	}
	for (i = i; i < 15; i++)
		H->figury[i] = H->figury[i + 1];
	H->figury[15].fig = PPOL;
}

int NebKolm(int FIG, int H)
{				/* zda je kral H ohrozen z kolmice FIGem */
	if (H == BILYH) {
		switch (FIG) {
		case CDAM:
		case CVEZ:
			return 1;
		}
	} else {
		switch (FIG) {
		case BDAM:
		case BVEZ:
			return 1;
		}
	}
	return 0;
}

int NebDiag(int FIG, int H)
{				/* zda je kral H ohrozen z diagonaly FIGem */
	if (H == BILYH) {
		switch (FIG) {
		case CDAM:
		case CSTR:
			return 1;
		}
	} else {
		switch (FIG) {
		case BDAM:
		case BSTR:
			return 1;
		}
	}
	return 0;
}

int NebJezd(int FIG, int H)
{				/* zda je kral H ohrozen jezdcem */
	switch (H) {
	case BILYH:
		if (FIG == CJEZ)
			return 1;
		break;
	case CERNYH:
		if (FIG == BJEZ)
			return 1;
		break;
	}
	return 0;
}

int JeVSachu(int ZH, THra * H)
{				/* Zda ZH je v sachu */
	int kx, ky, i, j;
	switch (ZH) {
	case BILYH:
		kx = H->bily.figury[0].pos.x;
		ky = H->bily.figury[0].pos.y;
		break;
	case CERNYH:
		kx = H->cerny.figury[0].pos.x;
		ky = H->cerny.figury[0].pos.y;
		break;
	}
	/* projed kolmice a diagonaly od krale ... */
	/* kolmice */
	i = kx + 1;
	j = ky;
	while (i <= 7 && (H->sachovnice[i][j] == PPOL))
		i++;		/* zprava */
	if (i <= 7 && NebKolm(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 1;
	j = ky;
	while (i >= 0 && (H->sachovnice[i][j] == PPOL))
		i--;		/* zleva */
	if (i >= 0 && NebKolm(H->sachovnice[i][j], ZH))
		return 1;
	i = kx;
	j = ky + 1;
	while (j <= 7 && (H->sachovnice[i][j] == PPOL))
		j++;		/* shora */
	if (j <= 7 && NebKolm(H->sachovnice[i][j], ZH))
		return 1;
	i = kx;
	j = ky - 1;
	while (j >= 0 && (H->sachovnice[i][j] == PPOL))
		j--;		/* zdola */
	if (j >= 0 && NebKolm(H->sachovnice[i][j], ZH))
		return 1;
	/* pesci */
	switch (ZH) {
	case BILYH:
		if (kx <= 6 && ky <= 6 && (H->sachovnice[kx + 1][ky + 1] == CPES))
			return 1;
		if (kx >= 1 && ky <= 6 && (H->sachovnice[kx - 1][ky + 1] == CPES))
			return 1;
		break;
	case CERNYH:
		if (kx <= 6 && ky >= 1 && (H->sachovnice[kx + 1][ky - 1] == BPES))
			return 1;
		if (kx >= 1 && ky >= 1 && (H->sachovnice[kx - 1][ky - 1] == BPES))
			return 1;
		break;
	}
	/* diagonalne */
	i = kx + 1;
	j = ky + 1;
	while (i <= 7 && j <= 7 && (H->sachovnice[i][j] == PPOL)) {
		i++;
		j++;
	}			/* zprzhor */
	if (i <= 7 && j <= 7 && NebDiag(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 1;
	j = ky + 1;
	while (i >= 0 && j <= 7 && (H->sachovnice[i][j] == PPOL)) {
		i--;
		j++;
	}			/* zlezhor */
	if (i >= 0 && j <= 7 && NebDiag(H->sachovnice[i][j], ZH))
		return 1;
	i = kx + 1;
	j = ky - 1;
	while (i <= 7 && j >= 0 && (H->sachovnice[i][j] == PPOL)) {
		i++;
		j--;
	}			/* zprzdol */
	if (i <= 7 && j >= 0 && NebDiag(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 1;
	j = ky - 1;
	while (i >= 0 && j >= 0 && (H->sachovnice[i][j] == PPOL)) {
		i--;
		j--;
	}			/* zlezdol */
	if (i >= 0 && j >= 0 && NebDiag(H->sachovnice[i][j], ZH))
		return 1;
	/* zkontroluj kone */
	i = kx + 1;
	j = ky + 2;
	if (i <= 7 && j <= 7 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx + 1;
	j = ky - 2;
	if (i <= 7 && j >= 0 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 1;
	j = ky + 2;
	if (i >= 0 && j <= 7 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 1;
	j = ky - 2;
	if (i >= 0 && j >= 0 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx + 2;
	j = ky + 1;
	if (i <= 7 && j <= 7 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx + 2;
	j = ky - 1;
	if (i <= 7 && j >= 0 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 2;
	j = ky + 1;
	if (i >= 0 && j <= 7 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	i = kx - 2;
	j = ky - 1;
	if (i >= 0 && j >= 0 && NebJezd(H->sachovnice[i][j], ZH))
		return 1;
	/* kralove nesmeji byt u sebe */
	if ((2 > abs((int) (H->bily.figury[0].pos.y - H->cerny.figury[0].pos.y))) &&
	    (2 > abs((int) (H->bily.figury[0].pos.x - H->cerny.figury[0].pos.x))))
		return 1;
	/* vse je OK */
	return 0;
}

int JeMat(THra * H)
{
	TMG mg;
	if (MoveGen(H, mg, 1))
		return 0;
	else if (JeVSachu(H->natahu, H))
		return 1;
	else
		return 0;
}

int JePat(THra * H)
{
	TMG mg;
	if (MoveGen(H, mg, 1))
		return 0;
	else if (JeVSachu(H->natahu, H))
		return 0;
	else
		return 1;
}

int SMove(THra * H, TTah t)
{
	int f;
	f = H->sachovnice[t.kam.x][t.kam.y];
	if (f != PPOL && f != BKRA && f != CKRA)	/* braci tah */
		return 1;
	if (JeVSachu(H->natahu, H))
		return 1;
	else
		return 0;
}
