/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * This file is part of SanKit -- A multiplatform set of C code
 * for reading and writing PGN formatted chess games. In addition
 * it can be used as an engine to determine in real time if proposed
 * moves are legal or not. It appears to generate near perfect PGN
 * from incorrectly formatted files.
 *
 * Copyright 1994 Steven J. Edwards All Rights Reserved.
 * Copyright 2009-2011 David Hoerl All Rights Reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*>>> sanatk.c: SAN project attack detection routines */

/* Revised: 1993.04.11 */

#include <stdio.h>

#include "sandef.h"
#include "sanvar.h"

#include "sanatk.h"

/*--> SANAttack: determine if a color attacks a square */
nonstatic
siT SANAttack(cT c, sqT sq)
{
	siT flag;
	dxT dx;
	dvT dv;
	xdvT xdv;
	sqptrT sqptr0, sqptr1;
	xsqptrT xsqptr0, xsqptr1;

/* set null result */

	flag = 0;

/* set origin square pointers  */

	sqptr0 = &gb.bv[sq];
	xsqptr0 = &gxb.xbv[map_xsq_sq(sq)];

/* process according to specified color */

	if(c == c_w) {
		/* pawn attacks */

		if((*(xsqptr0 + xdv_7) == cp_v0) && (*(sqptr0 + dv_7) == cp_wp)) {
			flag = 1;
		} else
		if((*(xsqptr0 + xdv_6) == cp_v0) && (*(sqptr0 + dv_6) == cp_wp)) {
			flag = 1;
		}

		/* knight attacks */

		if(!flag) {
			dx = dx_8;
			while(!flag && (dx <= dx_f)) {
				if((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
				   (*(sqptr0 + dvv[dx]) == cp_wn))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* orthogonal sweeps */

		if(!flag) {
			dx = dx_0;
			while(!flag && (dx <= dx_3)) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				sqptr1 = sqptr0;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(sqptr1 += dv) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wr)))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* diagonal sweeps */

		if(!flag) {
			dx = dx_4;
			while(!flag && (dx <= dx_7)) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				sqptr1 = sqptr0;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(sqptr1 += dv) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   ((*sqptr1 == cp_wq) || (*sqptr1 == cp_wb)))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* king attacks */

		if(!flag) {
			dx = dx_0;
			while(!flag && (dx <= dx_7)) {
				if((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
				   (*(sqptr0 + dvv[dx]) == cp_wk))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}
	} else {
		/* pawn attacks */

		if((*(xsqptr0 + xdv_4) == cp_v0) && (*(sqptr0 + dv_4) == cp_bp)) {
			flag = 1;
		} else
		if((*(xsqptr0 + xdv_5) == cp_v0) && (*(sqptr0 + dv_5) == cp_bp)) {
			flag = 1;
		}

		/* knight attacks */

		if(!flag) {
			dx = dx_8;
			while(!flag && (dx <= dx_f)) {
				if((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
				   (*(sqptr0 + dvv[dx]) == cp_bn))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* orthogonal sweeps */

		if(!flag) {
			dx = dx_0;
			while(!flag && (dx <= dx_3)) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				sqptr1 = sqptr0;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(sqptr1 += dv) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   ((*sqptr1 == cp_bq) || (*sqptr1 == cp_br)))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* diagonal sweeps */

		if(!flag) {
			dx = dx_4;
			while(!flag && (dx <= dx_7)) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				sqptr1 = sqptr0;
				xsqptr1 = xsqptr0;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(sqptr1 += dv) == cp_v0))
				{
				}
				if((*xsqptr1 == cp_v0) &&
				   ((*sqptr1 == cp_bq) || (*sqptr1 == cp_bb)))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}

		/* king attacks */

		if(!flag) {
			dx = dx_0;
			while(!flag && (dx <= dx_7)) {
				if((*(xsqptr0 + xdvv[dx]) == cp_v0) &&
				   (*(sqptr0 + dvv[dx]) == cp_bk))
				{
					flag = 1;
				} else {
					dx++;
				}
			}
		}
	}

	return flag;
}

/*--> SANWhiteAttacks: check if White attacks a square */
nonstatic
siT SANWhiteAttacks(sqT sq)
{
	return SANAttack(c_w, sq);
}

/*--> SANBlackAttacks: check if White attacks a square */
nonstatic
siT SANBlackAttacks(sqT sq)
{
	return SANAttack(c_b, sq);
}

/*--> SANWhiteInCheck: test for White in check */
nonstatic
siT SANWhiteInCheck(void)
{
	return SANAttack(c_b, plv[c_w][kingslot]);
}

/*--> SANBlackInCheck: test for Black in check */
nonstatic
siT SANBlackInCheck(void)
{
	return SANAttack(c_w, plv[c_b][kingslot]);
}

/*--> SANSetAttackersHalf: do contents of half of attackers vector */
static
void SANSetAttackersHalf(cT c)
{
	sqT frsq;
	siptrT siptr, baseptr;
	sqptrT frsqptr, tosqptr;
	siT i, n;
	pT frp;
	dxT dx;
	dvT dv;
	xsqptrT xsqptr0, xsqptr1;
	xdvT xdv;

/* set default entries as being not attacked */

	siptr = &atkcsqv[c][sq_a1];
	for(frsq = sq_a1; frsq <= sq_h8; frsq++) {
		*siptr++ = 0;
	}

/* assume piece vector is correct */

	n = plnv[c];
	frsqptr = &plv[c][0];
	for(i = 0; i < n; i++) {
		/* fetch from square invariants */

		frp = cv_p_cpv[gb.bv[frsq = *frsqptr]];
		baseptr = &atkcsqv[c][frsq];
		xsqptr0 = &gxb.xbv[map_xsq_sq(frsq)];

		/* process according to from piece */

		switch(frp) {
		case p_p:
			if(c == c_w) {
				if(*(xsqptr0 + xdv_4) == cp_v0) {
					siptr = baseptr + dv_4;
					*siptr |= bit << (byteW + p_p);
					(*siptr)++;
				}
				if(*(xsqptr0 + xdv_5) == cp_v0) {
					siptr = baseptr + dv_5;
					*siptr |= bit << (byteW + p_p);
					(*siptr)++;
				}
			} else {
				if(*(xsqptr0 + xdv_6) == cp_v0) {
					siptr = baseptr + dv_6;
					*siptr |= bit << (byteW + p_p);
					(*siptr)++;
				}
				if(*(xsqptr0 + xdv_7) == cp_v0) {
					siptr = baseptr + dv_7;
					*siptr |= bit << (byteW + p_p);
					(*siptr)++;
				}
			}
			break;

		case p_n:
			for(dx = dx_8; dx <= dx_f; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					siptr = baseptr + dvv[dx];
					*siptr |= bit << (byteW + p_n);
					(*siptr)++;
				}
			}
			break;

		case p_b:
			for(dx = dx_4; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				tosqptr = frsqptr;
				xsqptr1 = xsqptr0;
				siptr = baseptr;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(tosqptr += dv) == cp_v0))
				{
					siptr += dv;
					*siptr |= bit << (byteW + p_b);
					(*siptr)++;
				}
				if(*xsqptr1 == cp_v0) {
					siptr += dv;
					*siptr |= bit << (byteW + p_b);
					(*siptr)++;
				}
			}
			break;

		case p_r:
			for(dx = dx_0; dx <= dx_3; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				tosqptr = frsqptr;
				xsqptr1 = xsqptr0;
				siptr = baseptr;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(tosqptr += dv) == cp_v0))
				{
					siptr += dv;
					*siptr |= bit << (byteW + p_r);
					(*siptr)++;
				}
				if(*xsqptr1 == cp_v0) {
					siptr += dv;
					*siptr |= bit << (byteW + p_r);
					(*siptr)++;
				}
			}
			break;

		case p_q:
			for(dx = dx_0; dx <= dx_7; dx++) {
				dv = dvv[dx];
				xdv = xdvv[dx];
				tosqptr = frsqptr;
				xsqptr1 = xsqptr0;
				siptr = baseptr;
				while((*(xsqptr1 += xdv) == cp_v0) &&
					  (*(tosqptr += dv) == cp_v0))
				{
					siptr += dv;
					*siptr |= bit << (byteW + p_q);
					(*siptr)++;
				}
				if(*xsqptr1 == cp_v0) {
					siptr += dv;
					*siptr |= bit << (byteW + p_q);
					(*siptr)++;
				}
			}
			break;

		case p_k:
			for(dx = dx_0; dx <= dx_7; dx++) {
				if(*(xsqptr0 + xdvv[dx]) == cp_v0) {
					siptr = baseptr + dvv[dx];
					*siptr |= bit << (byteW + p_k);
					(*siptr)++;
				}
			}
			break;
		}

		/* next from square */

		frsqptr++;
	}

	return;
}

/*--> SANSetAttackers: set both halves of the attackers vector */
nonstatic
void SANSetAttackers(void)
{
/* "Wanna see my sprocket collection?" */

	SANSetAttackersHalf(c_w);
	SANSetAttackersHalf(c_b);

	return;
}

/*<<< sanatk.c: EOF */
