/* tsumedef.c
 *	this module generates a list of valid defending moves
 *
 *	This module is almost identical to tsumeatt.c
 *	The difference is that valid moves must result in the
 *	king no longer being in check, and the pieces move in the
 *	opposite direction.
 */

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

/* routines in tsumoved.c */
extern
STEM	def_pawn (),	def_lance (),	def_horse (),	def_silver (),
	def_gold (),	def_rook (),	def_bishop (),	def_king (),
	def_tokin (),	def_p_lance (),	def_p_horse (),	def_p_silver (),
	def_p_rook (),	def_p_bishop ();

/* routines in tsumechk.c	They return MATE or NULL */
extern
int	chk_pawn (),	chk_lance (),	chk_horse (),
	chk_silver (),	chk_gold (),	chk_rook (),
	chk_bishop (),	chk_p_rook (),	chk_p_bishop ();

int	o_king_x, o_king_y;

/*
 *	Set up an defend layer of the tree.
 *
 *	Search the board for defenders pieces
 *	Generate a list of possible moves for each piece.
 *	Test each move for escape from check.
 *	Generate list of drops that block check.
 */

STEM def_move ( old_b )
I_STATE old_b;
{	int	x, y, i, j, t1, list_size;
	STEM	poss_moves, move_list, drops_list, t_move, t_t_move;

	brdcpy ( curr_board, old_b->board );
	move_list = NULL;
	for ( y = 1; y < 10 ; y++ )
	for ( x = 1; x < 10; x++ )
	{	i = x + 9 * y;
		j = curr_board[i];
		switch ( j )
		{	case DEF_PAWN:
				poss_moves = def_pawn ( x, y );
				break;
			case DEF_LANCE:
				poss_moves = def_lance ( x, y );
				break;
			case DEF_HORSE:
				poss_moves = def_horse ( x, y );
				break;
			case DEF_SILVER:
				poss_moves = def_silver ( x, y );
				break;
			case DEF_GOLD:
				poss_moves = def_gold ( x, y );
				break;
			case DEF_KING:
				o_king_x = x;
				o_king_y = y;
				poss_moves = def_king ( x, y );
				break;
			case DEF_ROOK:
				poss_moves = def_rook ( x, y );
				break;
			case DEF_BISHOP:
				poss_moves = def_bishop ( x, y );
				break;
			case DEF_TOKIN:
				poss_moves = def_tokin ( x, y );
				break;
			case DEF_P_LANCE:
				poss_moves = def_p_lance ( x, y );
				break;
			case DEF_P_HORSE:
				poss_moves = def_p_horse ( x, y );
				break;
			case DEF_P_SILVER:
				poss_moves = def_p_silver ( x, y );
				break;
			case DEF_P_ROOK:
				poss_moves = def_p_rook ( x, y );
				break;
			case DEF_P_BISHOP:
				poss_moves = def_p_bishop ( x, y );
				break;
			default:
				poss_moves = NULL;
		};

		if ( poss_moves != NULL )
			tie ( poss_moves, &move_list );
	}

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

/* generate any possible drops */
/* scan board for drop points  */
/* check if a drop will block check */
/* if yes, generate a drop for each available pice type */
/* tack on drops to list of moves   */

	drops_list = NULL;
	t_move = move_list;
	while ( t_move != NULL )
	{	t_t_move = move_list;
		while ( t_t_move != t_move )
		{	if ( t_t_move->loc_to_x == t_move->loc_to_x &&
			     t_t_move->loc_to_y == t_move->loc_to_y )
				break;
			t_t_move = t_t_move->next;
		};

		x = t_move->loc_to_x;
		y = t_move->loc_to_y;

/* If we have already checked this position, don't do it again.
 * Equally, we can't drop if the position is occupied.
 */
		if ( curr_board[x+y*9] != NULL ||
		     t_t_move != t_move )
		{	t_move = t_move->next;
			continue;
		};

		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->promo_now = NO;
		poss_moves->capture = 0;
		poss_moves->loc_to_x = x;
		poss_moves->loc_to_y = y;
		poss_moves->piece_moving = DEF_PAWN;
		def_check ( &poss_moves );
/* throws away poss_moves if mate not blocked */

		if ( poss_moves == NULL )
		{	t_move = t_move->next;
			continue;
		};

		i = 0;
		while ( ( j = old_b->def_h[i++] ) != NULL )
		{	if ( i > 1 && j == old_b->def_h[i-2] )
				continue;
/* only check each type of piece once */

			switch ( j )
			{	case DEF_PAWN:
					t1 = ( y < 9 &&
				old_b->board[x+ 9] != DEF_PAWN &&
				old_b->board[x+18] != DEF_PAWN &&
				old_b->board[x+27] != DEF_PAWN &&
				old_b->board[x+36] != DEF_PAWN &&
				old_b->board[x+45] != DEF_PAWN &&
				old_b->board[x+54] != DEF_PAWN &&
				old_b->board[x+63] != DEF_PAWN &&
				old_b->board[x+72] != DEF_PAWN
						 ? t1 = j : NULL );
					break;
				case DEF_LANCE:
					t1 = ( y < 9 ? j : NULL );
				case DEF_HORSE:
					t1 = ( y < 8 ? j : NULL );
					break;
				case DEF_SILVER:
				case DEF_GOLD:
				case DEF_ROOK:
				case DEF_BISHOP:
					t1 = j;
					break;
				default:
					t1 = NULL;
/* corrupt data structure !!!!
 */			}

			if ( t1 != NULL )
			{	poss_moves->piece_moving = j;
				tie ( poss_moves, &drops_list );
				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->promo_now = NO;
				poss_moves->capture = 0;
				poss_moves->loc_to_x = x;
				poss_moves->loc_to_y = y;
			}
		};
		free ( poss_moves );
		t_move = t_move->next;
	}

	list_size = def_check ( &move_list );
	if ( list_size < min_list_len )		min_list_len = list_size;

	if ( drops_list != NULL )
		tie ( drops_list, &move_list );

/* Note: If move_list == NULL then there is no defense */
	return ( move_list );
}


int def_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, list_length;

	fi = list_length = 0;

	a_move = *move_l;

/* make the move and then test every attacking piece for mate	*/
/* trash the move if it results in mate				*/

	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 ( x = 1; x <= 9; x++ )
		{	for ( y = 1; y <= 9; y++ )
			{	i = curr_board[x + 9 * y];
	
				switch ( i )
				{
				case ATT_P_ROOK:
					t1 = chk_p_rook   ( x, y );
					break;
				case ATT_P_BISHOP :
					t1 = chk_p_bishop ( x, y );
					break;
				case ATT_ROOK:
					t1 = chk_rook     ( x, y );
					break;
				case ATT_BISHOP:
					t1 = chk_bishop   ( x, y );
					break;
				case ATT_PAWN:
					t1 = chk_pawn     ( x, y );
					break;
				case ATT_LANCE:
					t1 = chk_lance    ( x, y );
					break;
				case ATT_HORSE:
					t1 = chk_horse    ( x, y );
					break;
				case ATT_SILVER:
					t1 = chk_silver   ( x, y );
					break;
				case ATT_GOLD:
				case ATT_TOKIN:
				case ATT_P_LANCE:
				case ATT_P_HORSE:
				case ATT_P_SILVER:
					t1 = chk_gold     ( x, y );
					break;
				}
				if ( t1 == MATE )	break;
			};
			if ( t1 == MATE )	break;
		};

/* ends for, for 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;
			free ( t_move );
		}
		else
		{	list_length++;
			if ( a_move->piece_moving == DEF_KING )
			{	i = a_move->loc_to_x - king_x_pos;
				j = a_move->loc_to_y - king_y_pos;
			}
			else
			{	i = o_king_x - king_x_pos;
				j = o_king_y - king_y_pos;
			};
			a_move->distance = i * i + j * j;
			a_move = a_move->next;
		};
	};
	return ( list_length );
}

