/*P*/
/****************************************************************/
/*								*/
/* get_pre_command, accept					*/
/*								*/
/* These two routines handle the doubling cube. get_pre_command	*/
/* fills in a buffer if a double should be made by the		*/
/* person specified (this is the same routine for both black	*/
/* and white). Accept returns a char of eother 'Y' or 'N', as	*/
/* if the user had typed it in at the terminal.			*/
/*								*/
/****************************************************************/

#include	<stdio.h>
#include	"bkg.h"

get_pre_command( who, buf, owned, value )

int	who;
char	buf[];
int	owned, value;

	{

	int	b_count, w_count, diff, my_count, calc;

	buf[ 0 ] = '\0';

	/* Only double if the cube is either in the	*/
	/* middle, or is my half of the board.		*/

	if ( ( value < 64	    ) &&
	     ( ( owned == who	  ) ||
	       ( owned == NOBODY  ) ) )
		{	

		get_counts( who, &b_count, &w_count, &diff, &my_count );

		/* If your lead is 7.5% of your count, make	*/
		/* a first double. If it is 10.0% make a later	*/
		/* double.					*/

		calc = ( diff * 100 ) / my_count;

		if ( ( value == 1 ) &&
		     ( calc >= 8  ) )
			strcpy( buf, "double" );
		else
			if ( calc >= 10 )
				strcpy( buf, "double" );

		} /* look at situation */

	} /* get_pre_command */

char accept( who )

	{

	int	b_count, w_count, diff, my_count, calc;

	get_counts( who, &b_count, &w_count, &diff, &my_count );
	
	/* Accept a double any time you are less than	*/
	/* 15% behind in the game.			*/

	calc = ( diff * 100 ) / my_count;

	if ( calc > -15 )
		return( 'Y' );
	else
		return( 'N' );

	} /* accept */

/*P*/
/****************************************************************/
/*								*/
/* get_counts							*/
/*								*/
/* Calculate the counts on the board and return these values.	*/
/* "who" indicates the player requesting the counts. We return	*/
/* that players count in "my_count", and both in the others.	*/
/*								*/
/****************************************************************/

get_counts( who, b_count, w_count, diff, my_count )

int	who, *b_count, *w_count, *diff, *my_count;

	{
	
	int	i;

	*b_count = *w_count = 0;

	for( i = B_BAR; i < 25; i++ )
		*b_count += ( 25 - i ) * board[ i ][ BLACK ];

	for( i = W_BAR; i; i-- )
		*w_count += i * board[ i ][ WHITE ];

	if ( who == BLACK )
		*diff = *w_count - *b_count;
	else
		*diff = *b_count - *w_count;

	*my_count = ( who == WHITE ) ? *w_count : *b_count;

	} /* get_count */

/*P*/
/****************************************************************/
/*								*/
/* eval								*/
/*								*/
/* These sections control board position evaluation. An integer	*/
/* is returned to the caller denoting the worth of a particular	*/
/* board. The passed in board is a temp-type, that is, it is	*/
/* 3 deep. The [ 2 ] part of the array contains hit men that	*/
/* have been removed. If b_eval is called, for example, then	*/
/* test[ 15 ][ 2 ] tells if any white men have been bumped off	*/
/* of the 15 spot.						*/
/*								*/
/* It is up to the caller to make sure that the test board was	*/
/* "gotten to" via a legal move. See movegen.c for details.	*/
/*								*/
/* Needless to say, this is where the "smarts" are. These two	*/
/* functions are very critical to a "good" game player. Since	*/
/* I'm a 1/2 way good player, I have made these as good as I 	*/
/* know how; however, there is always room for a lot of late	*/
/* improvement by anyone who is more familiar with the "theory"	*/
/* than I am (that is just about anyone...).			*/
/*								*/
/****************************************************************/

/****************************************************************/
/*								*/
/* b_eval							*/
/*								*/
/* Evaluate the test board according to black's favor. Return	*/
/* an integer denoting how good the position is. Positive is	*/
/* better. The highest eval number is the "best" move.		*/
/*								*/
/****************************************************************/

b_eval( test, count )

int	test[ SIZE ][ 3 ], count;

	{

	char		buf[ 80 ];
	int		i, j, watch_it, score, quad, end_game, hit_val;

	score = 0;

	/* If we are heavy into testing, spit	*/
	/* out the entire board in decimal.	*/

	if ( debug == 3 )
		{
		char_at( 21, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ WHITE ] );
		char_at( 22, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ BLACK ] );
		char_at( 23, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ 2 ] );
		raw_keyboard();
		}

	/* Let them know we are still working	*/
	/* on a solution...			*/

	if ( count == 80 )
		write_at( 15, 65, "Thinking...", TEXT_COLOR );

	/* Test exception # 0 - we are in the	*/
	/* white's inner table, but we're going	*/
	/* to lose bad. in that case, we want	*/
	/* to hit anything we can!		*/

	for ( i = 25; i > 10; i-- )
		if ( test[ i ][ WHITE ] )
			break;

	if ( i == 10 )
		for ( ; i; i-- )
			if ( test[ i ][ 2 ] )
				score = 30000;

	/* Look for another exception - we may	*/
	/* be almost off of the board, but then	*/
	/* leave one and only one man open on a	*/
	/* particular bar. If that's the case,	*/
	/* we don't want to do that...		*/

	for( i = 24; i > 16; i-- )
		if ( test[ i ][ BLACK ] == 1 )
			break;

	if ( i > 16 )
		{

		watch_it = FALSE;

		for( j = 24; j; j-- )
			if ( test[ j ][ 2 ] )
				{
				watch_it = TRUE;
				break;
				}

		for( j = 25; j > i; j-- )
			if ( test[ j ][ WHITE ] )
				{
				watch_it = TRUE;
				break;
				}

		for( j = 16; j; j-- )
			if ( test[ j ][ BLACK ] )
				{
				watch_it = FALSE;
				break;
				}

		if ( watch_it )
			score = -30000;

		} /* exception 1 */

	/* Detect the end-game situation.	*/
	/* According to a Scientific American	*/
	/* article about 5 years ago, this	*/
	/* should be a smooth transition, and	*/
	/* not a boolean. Future fix?		*/
 	
	for( i = 1; i < 25; i++ )
		if ( test[ i ][ BLACK ] )
			break;

 	for( end_game = TRUE; i < 25; i++ )
		if ( ( test[ i ][ WHITE ] ) ||
		     ( test[ i ][ 2 ]     ) )
			{
			end_game = FALSE;
			break;
			}

	if ( end_game )
		{

		for( i = 1; i < 19; i++ )
			score -= test[ i ][ BLACK ] * ( 25 - i );
		for( ; i < 25; i++ )
			score -= test[ i ][ BLACK ];
		return( score );

		} /* end_game */
	else
		{

		for( i = 24; i; i-- )
			{

			quad = ( ( 24 - i ) / 6 ) + 1;

			/* If there is only one black player	*/
			/* here, then it is a disadvantage. But	*/
			/* how much depends on the possability	*/
			/* of getting hit, and where it is.	*/

			if ( test[ i ][ BLACK ] == 1 )
				{

				/* Check out every potential hitter	*/

				hit_val = ( i - 7 );
				for( j = i + 1; ( j < 26 ) && ( j < i + 12 ); j++ )
					switch( test[ j ][ WHITE ] )
						{

						case 0:		break;


						case 1:		hit_val += prob[ j - i ];
								break;

						case 2:		hit_val += prob[ j - i ] / 2;
								break;

						default:	hit_val += prob[ j - i ] * 2;

						} /* switch */

				/* If it's by the outer table, it's	*/
				/* not bad, since we come right back.	*/

				score -= hit_val * ( 4 - quad );

				} /* if */

			if ( test[ i ][ BLACK ] > 1 )
				{
				score += ( i - 7 );
				score += ( 4 - quad ) * 5;
				}

			/* Hit the white guys?	*/

			if ( test[ i ][ 2 ] )
				{

				score += quad * 15;
				for( j = 24; j > 16; j-- )
					if ( test[ j ][ BLACK ] > 1 )
						score += 5;
					else
						if ( test[ j ][ BLACK ] == 1 )
							score -= 3;

				} /* test inner tbl */

			} /* for i */

		return( score );

		} /* not end game */

	} /* b_eval */

/*P*/
/****************************************************************/
/*								*/
/* w_eval							*/
/*								*/
/* Evaluate the test board according to white's favor. Return	*/
/* an integer denoting how good the position is. This should	*/
/* be identical to the other one, except that all of the loops	*/
/* and values are reversed. Note, though, that taking the neg	*/
/* of b_eval is not the same thing! Also, since they should be	*/
/* close to the same, it is easy to test changes by making them	*/
/* to one or the other evaluator, and letting the machine play	*/
/* against itself for 100 games or so (overnight).		*/
/*								*/
/****************************************************************/

w_eval( test, count )

int	test[ SIZE ][ 3 ], count;

	{

	char		buf[ 80 ];
	int		i, j, watch_it, score, quad, end_game, hit_val;

	score = 0;

	/* If we are heavy into testing, spit	*/
	/* out the entire board in decimal.	*/

	if ( debug == 3 )
		{
		char_at( 21, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ WHITE ] );
		char_at( 22, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ BLACK ] );
		char_at( 23, 0, CTEOL, 0x07 );
		for( i = 0; i < 26; i++ )
			printf( "%02d ", test[ i ][ 2 ] );
		raw_keyboard();
		}

	/* Let them know we are still working	*/
	/* on a solution...			*/

	if ( count == 80 )
		write_at( 15, 65, "Hmmm.......", TEXT_COLOR );

	/* Test exception # 0 - we are in the	*/
	/* black's inner table, but we're going	*/
	/* to lose bad. in that case, we want	*/
	/* to hit anything we can!		*/

	for ( i = 0; i < 15; i++ )
		if ( test[ i ][ BLACK ] )
			break;

	if ( i == 15 )
		for ( ; i < 25; i++ )
			if ( test[ i ][ 2 ] )
				score = 30000;

	/* Look for another exception - we may	*/
	/* be almost off of the board, but then	*/
	/* leave one and only one man open on a	*/
	/* particular bar. If that's the case,	*/
	/* we don't want to do that...		*/

	for( i = 1; i < 9; i++ )
		if ( test[ i ][ WHITE ] == 1 )
			break;

	if ( i < 9 )
		{

		watch_it = FALSE;

		for( j = 1; j < 25; j++ )
			if ( test[ j ][ 2 ] )
				{
				watch_it = TRUE;
				break;
				}

		for( j = 0; j < i; j++ )
			if ( test[ j ][ BLACK ] )
				{
				watch_it = TRUE;
				break;
				}

		for( j = 9; j < 25; j++ )
			if ( test[ j ][ WHITE ] )
				{
				watch_it = FALSE;
				break;
				}

		if ( watch_it )
			score = -30000;

		} /* exception 1 */

	/* Detect the end-game situation.	*/

	for( i = 24; i; i-- )
		if ( test[ i ][ WHITE ] )
			break;

	for( end_game = TRUE; i; i-- )
		if ( ( test[ i ][ BLACK ] ) ||
		     ( test[ i ][ 2 ]     ) )
			{
			end_game = FALSE;
			break;
			}

	if ( end_game )
		{

		for( i = 24; i > 6; i-- )
			score -= test[ i ][ WHITE ] * i;
		for( ; i; i-- )
			score -= test[ i ][ WHITE ];
		return( score );

		} /* end_game */
	else
		{

		for( i = 1; i < 25; i++ )
			{

			quad = ( ( i - 1 ) / 6 ) + 1;

			if ( test[ i ][ WHITE ] == 1 )
				{

				hit_val = ( 18 - i );
				for( j = i - 1; ( j > -1 ) && ( j > i - 12 ); j-- )
					switch( test[ j ][ BLACK ] )
						{

						case 0:		break;


						case 1:		hit_val += prob[ i - j ];
								break;

						case 2:		hit_val += prob[ i - j ] / 2;
								break;

						default:	hit_val += prob[ i - j ] * 2;

						} /* switch */

				score -= hit_val * ( 4 - quad );

				} /* if */

			if ( test[ i ][ WHITE ] > 1 )
				{
				score += ( 18 - i );
				score += ( 4 - quad ) * 5;
				}

			/* Hit the black guys?	*/

			if ( test[ i ][ 2 ] )
				{

				score += quad * 15;
				for( j = 1; j < 9; j++ )
					if ( test[ j ][ WHITE ] > 1 )
						score += 5;
					else
						if ( test[ j ][ WHITE ] == 1 )
							score -= 3;

				} /* test inner tbl */

			} /* for i */

		return( score );

		} /* not end game */

	} /* w_eval */

