/* tsumeatt.c
 *	this module generates a list of valid attacking moves
 */

#include "tsume.h"
#include "tsumedat.h1"

/* These routines are in tsumove.c
/*	Each routine generates a list of all possible moves for the
/*	specified piece.
 */
extern
STEM	att_pawn (),	att_lance (),	att_horse (),	att_silver (),
	att_gold (),	att_rook (),	att_bishop (),	att_tokin (),
	att_p_lance (),	att_p_horse (),	att_p_silver (),att_p_rook (),
	att_p_bishop ();


/* These routines are in tsumechk.c
/*	Each routine tests to see if the specified piece at the supplied
/*	coordinates gives check.
 */
extern
int	chk_pawn (),	chk_lance (),	chk_horse (),
	chk_silver (),	chk_gold (),	chk_rook (),
	chk_bishop (),	chk_p_rook (),	chk_p_bishop ();

int	king_x, king_y;

/*
 *	Set up an attack layer of the tree.
 *
 *	Search the board for attackers pieces
 *	Generate a list of possible moves for each piece.
 *	Stop if a move captures the King.
 *	Test each move for direct check or for revealed check.
 *	Generate list of drops that give check.
 */
STEM att_move ( old_b )
I_STATE old_b;
{	int	x, y, i, j, t1;
	STEM	poss_moves, move_list;

	brdcpy ( curr_board, old_b->board );
/*	print_board ( old_b );	*/

	move_list = NULL;
	for ( y = 1; y < 10 ; y++ )
	{	for ( x = 1; x < 10; x++ )
		{	i = x + 9 * y;
			if ( curr_board[i] == DEF_KING )	break;
		};
		if ( curr_board[i] == DEF_KING )	break;
	};
	king_x = x;
	king_y = y;

	for ( y = 1; y < 10 ; y++ )
	for ( x = 1; x < 10; x++ )
	{	i = x + 9 * y;
		j = curr_board[i];
		switch ( j )
		{	case ATT_PAWN:
				poss_moves = att_pawn ( x, y );
				break;
			case ATT_LANCE:
				poss_moves = att_lance ( x, y );
				break;
			case ATT_HORSE:
				poss_moves = att_horse ( x, y );
				break;
			case ATT_SILVER:
				poss_moves = att_silver ( x, y );
				break;
			case ATT_GOLD:
				poss_moves = att_gold ( x, y );
				break;
			case ATT_ROOK:
				poss_moves = att_rook ( x, y );
				break;
			case ATT_BISHOP:
				poss_moves = att_bishop ( x, y );
				break;
			case ATT_TOKIN:
				poss_moves = att_tokin ( x, y );
				break;
			case ATT_P_LANCE:
				poss_moves = att_p_lance ( x, y );
				break;
			case ATT_P_HORSE:
				poss_moves = att_p_horse ( x, y );
				break;
			case ATT_P_SILVER:
				poss_moves = att_p_silver ( x, y );
				break;
			case ATT_P_ROOK:
				poss_moves = att_p_rook ( x, y );
				break;
			case ATT_P_BISHOP:
				poss_moves = att_p_bishop ( x, y );
				break;
			default:
				poss_moves = NULL;
		};

/* this step will remove those moves that do not result in check */
		if ( poss_moves != NULL )
			check_check ( &poss_moves );

/* If we have any moves left, we add them to the complete list for 
/* the current board state.
 */
		if ( poss_moves != NULL )
			tie ( poss_moves, &move_list );
	}

/* move list now holds a full list of valid moves */

/* generate any possible drops */
	i = 0;
	while ( ( j = old_b->att_h[i++] ) != NULL )
	{	if ( i > 1 && j == old_b->att_h[i-2] )
			break;
/* only check each type of piece once
/*		printf ( "drop ind %d bit %d\n", i, j );
 */
		for ( x = 1; x < 10 ; x++ )
		for ( y = 1; y < 10 ; y++ )
		{	if ( curr_board[x+y*9] == NULL )
			{	switch ( j )
				{
				case ATT_PAWN:
/* This madness is to ensure that only one pawn exists on a file */
					t1 =
					 ( y != 1 &&
					   old_b->board[x+18] != ATT_PAWN &&
					   old_b->board[x+27] != ATT_PAWN &&
					   old_b->board[x+36] != ATT_PAWN &&
					   old_b->board[x+45] != ATT_PAWN &&
					   old_b->board[x+54] != ATT_PAWN &&
					   old_b->board[x+63] != ATT_PAWN &&
					   old_b->board[x+72] != ATT_PAWN &&
					   old_b->board[x+81] != ATT_PAWN ?
					   chk_pawn (x,y) : NULL );
					break;
				case ATT_LANCE:
					t1 =
					  ( y == 1 ? NULL : chk_lance (x,y) );
					break;
				case ATT_HORSE:
					t1 =
					  ( y < 3 ? NULL : chk_horse (x,y) );
					break;
				case ATT_SILVER:
					t1 = chk_silver (x,y);
					break;
				case ATT_GOLD:
					t1 = chk_gold (x,y);
					break;
				case ATT_ROOK:
					t1 = chk_rook (x,y);
					break;
				case ATT_BISHOP:
					t1 = chk_bishop (x,y);
					break;
				default:
					t1 = NULL;
/* corrupt data structure !!!!
 */				}

				if ( t1 == MATE )
				{	poss_moves = ( STEM ) malloc
						( sizeof ( LEAF ));
					poss_moves->next_level   =
					poss_moves->next         =
					poss_moves->prev         = NULL;
					poss_moves->loc_from_x   =
					poss_moves->loc_from_y   = 0;
					poss_moves->loc_to_x     = x;
					poss_moves->loc_to_y     = y;
					poss_moves->promo_now    = NO;
					poss_moves->capture      = 0;
					poss_moves->distance     = 0;
					poss_moves->piece_moving = j;
					tie ( poss_moves, &move_list );
/*					printf ( "Drop!\n" );
 */				}
			}
		}
	}
/* Note: If move_list == NULL then there is no attack */
	return ( move_list );
}


int check_check ( move_l )
STEM	*move_l;
{	STEM	a_move, t_move;
	int	f_p_x[8], f_p_y[8];
	int	i, j, k, fi, t1, x, y;

	fi = 0;

	a_move = *move_l;

	for ( x = 1; x <= 9; x++ )
	for ( y = 1; y <= 9; y++ )
	{	i = curr_board[x + 9 * y];
		if ( i == ATT_LANCE ||
		     i == ATT_ROOK ||
		     i == ATT_P_ROOK ||
		     i == ATT_BISHOP ||
		     i == ATT_P_BISHOP )
		{	f_p_x[fi] = x;
			f_p_y[fi++] = y;
		}
	}

	while ( a_move != NULL )
	{	curr_board[a_move->loc_to_x + 9 * a_move->loc_to_y] =
			a_move->piece_moving + 10 * a_move->promo_now;
		curr_board[a_move->loc_from_x + 9 * a_move->loc_from_y] =
			NULL;

		t1 = NULL;
		for ( i = 0; i < fi && t1 != MATE ; i++ )
		{	j = curr_board[ f_p_x[i] + 9 * f_p_y[i] ];
			switch ( j )
			{
			case ATT_LANCE:
				t1 = chk_lance   ( f_p_x[i],f_p_y[i] );
				break;
			case ATT_P_ROOK:
				t1 = chk_p_rook  ( f_p_x[i],f_p_y[i] );
				break;
			case ATT_P_BISHOP :
				t1 = chk_p_bishop( f_p_x[i],f_p_y[i] );
				break;
			case ATT_ROOK:
				t1 = chk_rook    ( f_p_x[i],f_p_y[i] );
				break;
			case ATT_BISHOP:
				t1 = chk_bishop  ( f_p_x[i],f_p_y[i] );
			}
		};

		if ( t1 != MATE )
		{
			switch ( a_move->piece_moving + 10* a_move->promo_now)
			{
			case ATT_PAWN:
				t1 = chk_pawn ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_LANCE:
				t1 = chk_lance ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_HORSE:
				t1 = chk_horse ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_SILVER:
				t1 = chk_silver ( a_move->loc_to_x,
						      a_move->loc_to_y );
				break;
			case ATT_GOLD:
				t1 = chk_gold ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_ROOK:
				t1 = chk_rook ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_BISHOP:
				t1 = chk_bishop ( a_move->loc_to_x,
						      a_move->loc_to_y );
				break;
			case ATT_TOKIN:
				t1 = chk_gold ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_P_LANCE:
				t1 = chk_gold ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_P_HORSE:
				t1 = chk_gold ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_P_SILVER:
				t1 = chk_gold ( a_move->loc_to_x,
						    a_move->loc_to_y );
				break;
			case ATT_P_ROOK:
				t1 = chk_p_rook ( a_move->loc_to_x,
						      a_move->loc_to_y );
				break;
			case ATT_P_BISHOP:
				t1 = chk_p_bishop ( a_move->loc_to_x,
						        a_move->loc_to_y );
				break;
			};
		}
/* ends if and case */

/* reset curr_board for next move */
		curr_board[a_move->loc_to_x + 9 * a_move->loc_to_y] = 
			a_move->capture;
		curr_board[a_move->loc_from_x + 9 * a_move->loc_from_y] =
			a_move->piece_moving;

/* If no mate this move is not check so we discard it.
/* In any case we step to the next move to be tested.
 */
		if ( t1 != MATE )
		{	t_move = a_move;
			if ( a_move->prev != NULL )
				a_move->prev->next = a_move->next;
			else	*move_l = a_move->next;
			if ( a_move->next != NULL )
				a_move->next->prev = a_move->prev;
			a_move = a_move->next;
			t_move->prev = t_move->next = NULL;
/* printf ("no mate - free %d", t_move ); */
			free ( t_move );
		}
		else
		{	i = a_move->loc_to_x - king_x;
			j = a_move->loc_to_y - king_y;
			a_move->distance = i * i + j * j;
			i = a_move->loc_from_x - king_x;
			j = a_move->loc_from_y - king_y;
			a_move->distance -= i * i + j * j;
			a_move = a_move->next;
		}

	};
}
