#include <stdio.h>
#include <string.h>
#include "yahtzee.h"

/*
 * (c)1992 by orest zborowski
 */

/*
**	if defined, DEBUG will cause the computer to print out a bunch of
**	information as its trying to decide what to do with its rolls
#define DEBUG
*/

extern int num_players;
extern Player players[];
extern int dice_values[];

#ifdef DEBUG

static char *upper_headers[NUM_UPPER] =
{
	"(a) 1",
	"(b) 2",
	"(c) 3",
	"(d) 4",
	"(e) 5",
	"(f) 6"
};

static char *lower_headers[NUM_LOWER] =
{
	"(g) 3 of a Kind",
	"(h) 4 of a Kind",
	"(i) Full House",
	"(j) Small Straight",
	"(k) Large Straight",
	"(l) Yahtzee",
	"(m) Chance",
};
#endif

static int numrolls = 0;

/*
**	questions are:
**		0:	none
**		1:	"what dice to roll again?"
**		2:	"where do you want to put that?"
*/

static struct
{
	int value;
	char rerolls[20];
} bc_table[NUM_FIELDS];


/*
**	depending on the dice rolls, we fill in the choice table.  if
**	for a particular choice the rolls are good, we put an appropriate
**	value in the table.  we also give which die need to be rerolled.
**
**	basically, the value system is based off the highest score possible
**	rolling the dice - all 6 (6 x 5 = 30).  so the best any of the upper
**	ranks can get is 30.
*/

static int throwaway[NUM_FIELDS] =
{
	4,      /* 1 */
	3,      /* 2 */
	2,      /* 3 */
	2,      /* 4 */
	1,      /* 5 */
	1,      /* 6 */
	3,      /* 3 of a kind */
	5,      /* 4 of a kind */
	4,      /* Full House */
	3,      /* Small straight */
	5,      /* Large straight */
	4,      /* Yahtzee */
	0,      /* Chance */
};

void
build_table(int player)
{
	int i;
	int j;
	int k;
	int d;
	int d2;
	int overflow;
	char foo[10];
#ifdef DEBUG
	char fred[1024];
#endif

	++numrolls;

	for (i = 0; i < NUM_FIELDS; ++i)
	{
		if (players[player].used[i])
			bc_table[i].value = -99;
		else
			bc_table[i].value = throwaway[i];

		strcpy(bc_table[i].rerolls, "1 2 3 4 5");
	}

/*
**	HANDLING UPPER SLOTS
*/

/*
**	first, we calculate the overflow of the upper ranks. that is, we
**	count all the points we have left over from our 3-of-all rule
**	if we get 3 of all in the upper ranks, we get a bonus, so if
**	we get 4 of something, that means a lower roll may be acceptable,
**	as long as we remain in the running for a bonus.  overflow can
**	be negative as well, in which case throwaway rolls are not
**	encouraged, and a high roll will get a nice boost
*/
	overflow = 0;

	for (i = 0; i < NUM_UPPER; ++i)
	{
		if (players[player].used[i])
			continue;

		overflow += (count(i+1) - 3) * (i+1);
	}

	for (i = 0; i < NUM_UPPER; ++i)
	{
		if (players[player].used[i])
			continue;

		bc_table[i].rerolls[0] = '\0';

		for (d = 0; d < 5; ++d)
		{
			if (dice_values[d] != i + 1)
			{
				sprintf(foo, "%d ", d + 1);

				strcat(bc_table[i].rerolls, foo);
			}
		}

/*
**	ok. now we set a base value on the roll based on its count and
**	how much it is worth to us.
*/
		bc_table[i].value = count(i+1) * 8;

/*
**	we have to play games with the bonus.
**	if we already have a bonus, then all free slots are candidates for
**		throwing away - we only do this when there are no more rolls
**	if this would get us a bonus, we make it very attractive
**
**	if we get 3 of everything on the top, we get a bonus. so...
**	if we have more than 3, we make the choice more attractive.
**	if less than 3, we make it less attractive.
**	if our overflow (any that are more than 3, summed up) covers up
**		our lack (if we only have 2, and there were 4 6's), we
**		dont penalize ourselves as much (since we're still in the
**		running for a bonus)
*/

		if (upper_total(player) >= 63)
		{
			if (numrolls > 2)
				bc_table[i].value += 10;
		}

		else if (upper_total(player) + count(i+1) * (i+1) >= 63)
		{
			bc_table[i].value += 35;
		}

		if (count(i+1) < 3)
		{
			if (overflow < (3 - count(i+1)) * (i+1))
				bc_table[i].value -= (3 - count(i+1)) * 2;
		}

		else if (count(i+1) > 3)
		{
			bc_table[i].value += (count(i+1) - 3) * 2;
		}
	}

/*
**	HANDLING LOWER SLOTS
*/

/*
**	first, we look for potential.  these values will be larger than the
**	single rolls but less than the made rolls (or those with higher value)
**
**	we also do such thinking only if we're not supposed to be looking just
**	for the best combinations...
*/
	if (numrolls < 3)
	{
/*
**	searching for large straight... here we chicken out and only look at
**	runs which might have possibilities
*/
		if (!players[player].used[H_LS])
		{
			for (i = 4; i > 0; --i)
			{
				d2 = find_straight(i, 0);

				if (d2 == 0)
					continue;

				bc_table[H_LS].value = (40 * i) / 5;

				bc_table[H_LS].rerolls[0] = '\0';

				for (d = 1; d < 7; ++d)
				{
					if (count(d) > 0)
					{
						if (d < d2 || d >= d2 + i)
							k = count(d);

						else
							k = count(d) - 1;

						if (k < 1)
							continue;

						for (j = 0; j < 5; ++j)
						{
							if (dice_values[j]!=d)
								continue;

							sprintf(foo, "%d ",
							  j + 1);

							strcat(
							 bc_table[H_LS].rerolls,
							  foo);

							if (!--k)
								break;
						}
					}
				}

				break;
			}
		}
/*
**	searching for small straight... here we chicken out and only look at
**	runs which might have possibilities
*/
		if (!players[player].used[H_SS])
		{
			for (i = 3; i > 0; --i)
			{
				d2 = find_straight(i, 0);

				if (d2 == 0)
					continue;

				bc_table[H_SS].value = (30 * i) / 4;

				bc_table[H_SS].rerolls[0] = '\0';

				for (d = 1; d < 7; ++d)
				{
					if (count(d) > 0)
					{
						if (d < d2 || d >= d2 + i)
							k = count(d);

						else
							k = count(d) - 1;

						if (k < 1)
							continue;

						for (j = 0; j < 5; ++j)
						{
							if (dice_values[j]!=d)
								continue;

							sprintf(foo, "%d ",
							  j + 1);

							strcat(
							 bc_table[H_SS].rerolls,
							  foo);

							if (!--k)
								break;
						}
					}
				}

				break;
			}
		}
/*
**	searching for 3 of a kind
*/
		if (!players[player].used[H_3])
		{
			for (i = 2; i > 0; --i)
			{
				for (d = 6; d > 0; --d)
				{
					if (count(d) >= i)
						break;
				}

				if (d == 0)
					continue;

				bc_table[H_3].rerolls[0] = '\0';

				bc_table[H_3].value = (d * i);

				for (j = 0; j < 5; ++j)
					if (dice_values[j] != d)
					{
						sprintf(foo, "%d ", j + 1);

						strcat(bc_table[H_3].rerolls,
						  foo);
					}

				break;
			}
		}
/*
**	searching for 4 of a kind
*/
		if (!players[player].used[H_4])
		{
			for (i = 3; i > 0; --i)
			{
				for (d = 6; d > 0; --d)
				{
					if (count(d) >= i)
						break;
				}

				if (d == 0)
					continue;

				bc_table[H_4].value = (d * i);

				bc_table[H_4].rerolls[0] = '\0';

				for (j = 0; j < 5; ++j)
					if (dice_values[j] != d)
					{
						sprintf(foo, "%d ", j + 1);

						strcat(bc_table[H_4].rerolls,
						  foo);
					}

				break;
			}
		}

/*
**	searching for yahtzee... we can't set the potential value too high
**	because if we fail, the value will be no better than 4 of a kind (or so)
**	so, we make scoring the same as for 3-4 of a kind (this is 5 of a kind!)
*/
		if (!players[player].used[H_YA])
		{
			for (i = 4; i > 0; --i)
			{
				for (d = 6; d > 0; --d)
				{
					if (count(d) >= i)
						break;
				}

				if (d == 0)
					continue;

				bc_table[H_YA].value = (d * i);

				bc_table[H_YA].rerolls[0] = '\0';

				for (j = 0; j < 5; ++j)
					if (dice_values[j] != d)
					{
						sprintf(foo, "%d ", j + 1);

						strcat(bc_table[H_YA].rerolls,
						  foo);
					}

				break;
			}
		}

/*
**	searching for full house
*/
		if (!players[player].used[H_FH])
		{
			for (i = 4; i > 0; --i)
			{
				d = find_n_of_a_kind(i, 0);

				if (d == 0)
					continue;

				for (j = i; j > 0; --j)
				{
					d2 = find_n_of_a_kind(j, d);

					if (d2 > 0)
						break;
				}

				if (j == 0)
					continue;

				bc_table[H_FH].rerolls[0] = '\0';

				bc_table[H_FH].value = (i * 24 + j * 36) / 6;

				for (i = 0; i < 5; ++i)
				{
					if (dice_values[i] != d &&
					  dice_values[i] != d2)
					{
						sprintf(foo, "%d ", i + 1);

						strcat(bc_table[H_FH].rerolls,
						  foo);
					}
				}

				break;
			}
		}
	}

/*
**	now we look hard at what we got
*/
	if (!players[player].used[H_SS] && find_straight(4, 0, 0))
	{
		d = find_straight(4, 0, 0);

		for (i = 0; i < 5; ++i)
			if (count(dice_values[i]) > 1 ||
			  dice_values[i] < d || dice_values[i] > d + 3)
			{
				sprintf(bc_table[H_SS].rerolls, "%d", i + 1);

				break;
			}

		bc_table[H_SS].value = 30;
	}

	if (!players[player].used[H_LS] && find_straight(5, 0, 0))
	{
		bc_table[H_LS].value = 40;

		bc_table[H_LS].rerolls[0] = '\0';
	}

	if (!players[player].used[H_CH] && numrolls > 2)
	{
		bc_table[H_CH].value = add_dice();

		if (bc_table[H_CH].value < 20)
			bc_table[H_CH].value /= 2;

		bc_table[H_CH].rerolls[0] = '\0';

		for (i = 0; i < 5; ++i)
			if (dice_values[i] < 4)
			{
				sprintf(foo, "%d ", i + 1);

				strcat(bc_table[H_CH].rerolls, foo);
			}
	}

	if (!players[player].used[H_FH])
	{
		d = find_n_of_a_kind(3, 0);

		if (d != 0)
		{
			if (find_n_of_a_kind(2, d))
			{
				bc_table[H_FH].value = 25;

				bc_table[H_FH].rerolls[0] = '\0';
			}
		}
	}

	if (!players[player].used[H_3])
	{
		d = find_n_of_a_kind(3, 0);

		if (d != 0)
		{
			bc_table[H_3].value = add_dice();

			bc_table[H_3].rerolls[0] = '\0';

			for (i = 0; i < 5; ++i)
				if (d != dice_values[i])
				{
					sprintf(foo, "%d ", i + 1);

					strcat(bc_table[H_3].rerolls, foo);
				}
		}
	}

	if (!players[player].used[H_4])
	{
		d = find_n_of_a_kind(4, 0);

		if (d != 0)
		{
/*
**	there will be a tie between 3 of a kind and 4 of a kind. we add 1
**	to break the tie in favor of 4 of a kind
*/
			bc_table[H_4].value = add_dice() + 1;

			bc_table[H_4].rerolls[0] = '\0';

			for (i = 0; i < 5; ++i)
				if (d != dice_values[i])
				{
					sprintf(foo, "%d ", i + 1);

					strcat(bc_table[H_4].rerolls, foo);
				}
		}
	}

	if (find_n_of_a_kind(5, 0))
	{

		if (players[player].used[H_YA] &&
		  players[player].score[H_YA] == 0)
			bc_table[H_YA].value = -99;	/* scratch */

		else
			bc_table[H_YA].value = 150;	/* so he will use it! */
		
	}


#ifdef DEBUG
	for (i = 0; i < NUM_FIELDS; ++i)
	{
		sprintf(fred, "%s : VALUE = %d REROLLS='%s'", 
		  (i < NUM_UPPER) ? upper_headers[i] : lower_headers[i - NUM_UPPER],
		  bc_table[i].value, bc_table[i].rerolls);

		query(-1, 0, fred, foo, sizeof(foo));
	}
#endif
}

void
bc_1(int player, char *buf, int bufsiz)
{
	int i;
	int best;
	int bestv;
#ifdef DEBUG
	char fred[1024];
#endif

	build_table(player);

	best = 0;

	bestv = -99;

	for (i = NUM_FIELDS-1; i >= 0; --i)
		if (bc_table[i].value >= bestv)
		{
			best = i;

			bestv = bc_table[i].value;
		}

#ifdef DEBUG
		sprintf(fred, "<<BEST>> %s : VALUE = %d REROLLS='%s'", 
		  (best < NUM_UPPER) ? upper_headers[best] : lower_headers[best - NUM_UPPER],
		  bc_table[best].value, bc_table[best].rerolls);

		query(-1, 0, fred, fred, sizeof(fred));
#endif

	strcpy(buf, bc_table[best].rerolls);
}

/*
**	what we do here is generate a table of all the choices then choose
**	the highest value one.  in case of a tie, we go for the lower choice
**	cause higher choices tend to be easier to better
*/

void
bc_2(int player, char *buf, int bufsiz)
{
	int i;
	int best;
	int bestv;
#ifdef DEBUG
	char fred[1024];
#endif

	numrolls = 2;				/* in case skipped middle */

	build_table(player);

	numrolls = 0;				/* for next time */

	best = 0;

	bestv = -99;

	for (i = NUM_FIELDS-1; i >= 0; --i)
		if (player % 2)
		{
			if (bc_table[i].value > bestv)
			{
				best = i;

				bestv = bc_table[i].value;
			}
		}

		else
		{
			if (bc_table[i].value >= bestv)
			{
				best = i;

				bestv = bc_table[i].value;
			}
		}

#ifdef DEBUG
		sprintf(fred, "<<BEST>> %s : VALUE = %d REROLLS='%s'", 
		  (best < NUM_UPPER) ? upper_headers[best] : lower_headers[best - NUM_UPPER],
		  bc_table[best].value, bc_table[best].rerolls);

		query(-1, 0, fred, fred, sizeof(fred));
#endif

	sprintf(buf, "%c", best + 'a');
}

void
be_computer(int player, int question, char *buf, int bufsiz)
{
	*buf = '\0';

	switch(question)
	{
		case 1:
			bc_1(player, buf, bufsiz);
			break;

		case 2:
			bc_2(player, buf, bufsiz);
			break;

		default:
			strcpy(buf, "Huh?");
			break;
	}
}
