DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦862f9efef⟧ TextFile

    Length: 14014 (0x36be)
    Types: TextFile
    Names: »strategies.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Cubes/strategies.c« 

TextFile

/*	vi:set sw=4 ts=4: */
#ifndef	lint
static char	sccsid[] = "@(#)strategies.c 5.1 (G.M. Paris) 89/01/22";
#endif	lint

/*
**
**	cubes 5.1  Copyright 1989 Gregory M. Paris
**		Permission granted to redistribute on a no charge basis.
**		All other rights are reserved.
**
*/

#include	<stdio.h>
#include	<syslog.h>
#include	"cubes.h"

extern boolean	jokermode;
extern boolean	sameface();
extern char	   *malloc();

#define	P_HAND	(NDICE * P_ACE)		/* a threshold */

/*
**	basic: (formerly) the most basic strategy
*/
static
basic(pd, need)
diceset	   *pd;
int			need;
{
	/*
	**	The basic strategy doesn't use need.
	*/
#ifdef	lint
	need = need;
#endif	lint

	/*
	**	Respect a complete dice set.
	*/
	if(pd->d_rolling == 0)
		return;

	/*
	**	If we're one away from All_of_a_kind, we're done.
	*/
	if(pd->d_rolling == 1) {
		if(sameface(pd, Ace, True) == True)
			return;
		if(sameface(pd, Five, True) == True)
			return;
		if(jokermode == True && sameface(pd, Joker, True) == True)
			return;
	}

	/*
	**	Discard Jokers and Fives.
	*/
	if(jokermode == True)
		nojokers(pd);
	nofives(pd);
}

/*
**	merrier: the more dice to throw, the merrier
*/
static
merrier(pd, need)
diceset	   *pd;
int			need;
{
	diceset	temp;

	/*
	**	The merrier strategy doesn't use need.
	*/
#ifdef	lint
	need = need;
#endif	lint

	/*
	**	Respect a complete dice set.
	*/
	if(pd->d_rolling == 0)
		return;

	/*
	**	Discard Jokers, Fives, and Aces if the result is three or more dice.
	*/
	temp = *pd;
	if(jokermode == True)
		nojokers(&temp);
	nofives(&temp);
	noaces(&temp);
	if(temp.d_rolling >= THREE)
		*pd = temp;
}

/*
**	respect: Respect the power of the Ace.
*/
static
respect(pd, need)
diceset	   *pd;
int			need;
{
	diceset	temp;

	/*
	**	We've completed all dice.  Try discarding Jokers and Fives.
	**	If the result is one die to roll and all Aces showing,
	**	then do it -- going for All_of_a_kind in Aces.
	*/
	if(pd->d_rolling == 0) {
		if(need > 0 && need < P_ACEMULT * P_AOKMULT)
			return;
		if(pd->d_pts_turn >= P_HAND)
			return;
		temp = *pd;
		if(jokermode == True)
			nojokers(&temp);
		nofives(&temp);
		if(temp.d_rolling == 1 && sameface(&temp, Ace, True) == True)
			*pd = temp;
		return;
	}

	/*
	**	Don't discard Aces if we're one away from All_of_a_kind.
	*/
	if(pd->d_rolling == 1)
		if(sameface(pd, Ace, True) == True)
			return;

	/*
	**	If we've got some points accumulated, we must be a bit desperate
	**	to want to roll again.  Improve our chances of getting something
	**	by scrapping junky Small_straights, freeing an Ace.
	*/
	if(pd->d_best == Small_straight)
		if(need > P_SMSTR || (need == 0 && pd->d_pts_turn > P_SMSTR))
			noacesmall(pd);

	/*
	**	Get rid of 3o'kind in deuces.  Scrap Jokers and Fives.
	*/
	if(pd->d_best == Three_of_a_kind)
		no3deuce(pd);
	if(jokermode == True)
		nojokers(pd);
	nofives(pd);

	/*
	**	Discard Aces if we end up with three or more dice.
	*/
	temp = *pd;
	noaces(&temp);
	if(temp.d_rolling >= THREE)
		*pd = temp;
}

/*
**	twohater: doesn't like 3o'kind in twos
*/
static
twohater(pd, need)
diceset	   *pd;
int			need;
{
	/*
	**	The twohater strategy doesn't use need.
	*/
#ifdef	lint
	need = need;
#endif	lint

	/*
	**	Respect completed dice set.
	*/
	if(pd->d_rolling == 0)
		return;

	/*
	**	Hates Jokers even more than 3o'kind in twos.
	*/
	if(jokermode == True)
		nojokers(pd);

	/*
	**	Prefers Fives and Aces over 3o'kind in twos.
	*/
	if(pd->d_best == Three_of_a_kind)
		no3deuce(pd);

	/*
	**	Discard Fives, but only discard Aces if
	**	we're already rolling more than one die.
	*/
	nofives(pd);
	if(pd->d_rolling > 1)
		noaces(pd);
}

/*
**	greedy: Tries for All_of_a_kind in Aces, Fives, and Jokers.
*/
static
greedy(pd, need)
diceset	   *pd;
int			need;
{
	diceset	temp;
	int		d, held, jokers;

	/*
	**	We've completed all dice.  If a single discard can get us
	**	closer to All_of_a_kind in Aces, Fives or Jokers, do it.
	*/
	if(pd->d_rolling == 0) {
		if(pd->d_pts_turn >= P_HAND)
			return;

		/*
		**	Discard Fives and Aces.  Check for all Jokers.
		*/
		if(jokermode == True) {
			if(need > 0 && need < P_JOKERMULT * P_AOKMULT)
				return;
			temp = *pd;
			nofives(&temp);
			noaces(&temp);
			if(temp.d_rolling == 1 && sameface(&temp, Joker, True) == True) {
				*pd = temp;
				return;
			}
		}

		/*
		**	Discard Jokers and Fives.  Check for all Aces.
		*/
		if(need > 0 && need < P_ACEMULT * P_AOKMULT)
			return;
		temp = *pd;
		if(jokermode == True)
			nojokers(&temp);
		nofives(&temp);
		if(temp.d_rolling == 1 && sameface(&temp, Ace, True) == True) {
			*pd = temp;
			return;
		}

		/*
		**	Discard Jokers and Aces.  Check for all Fives.
		*/
		if(need > 0 && need < FIVE * P_AOKMULT)
			return;
		temp = *pd;
		if(jokermode == True)
			nojokers(&temp);
		noaces(&temp);
		if(temp.d_rolling == 1 && sameface(&temp, Five, True) == True) {
			*pd = temp;
			return;
		}

		return;
	}

	/*
	**	On the first roll, if we have the choice between holding Jokers
	**	and Fives, choose the Jokers -- going for AOK in Jokers.
	*/
	if(jokermode == True) {
		if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
			if(pd->d_pts_turn == 0 && pd->d_best == Five) {
				held = jokers = 0;
				for(d = 0;d < NDICE;++d) {
					switch(pd->d_comb[d]) {
					case Previous:	++held; break;
					case Joker:		++jokers; break;
					}
				}
				if(held == 0 && jokers > 0)
					nofives(pd);
				return;
			}
		}
	}

	/*
	**	Small_straights make getting 5o'kind difficult, but if
	**	ASMSTR is defined, they can be converted to Straights,
	**	giving us another chance with all dice.  The Small_straight
	**	containing an Ace is the most difficult to convert.
	**	If no ASMSTR, discard all Small_straights, otherwise
	**	discard only the tough kind.
	*/
	if(pd->d_best == Small_straight) {
#ifdef	ASMSTR
		noacesmall(pd);		/* this kind too hard to convert */
#else	ASMSTR
		nosmall(pd);		/* don't like any Small_straights */
#endif	ASMSTR
		return;
	}

	/*
	**	Try to get all Aces showing.  If we can, we're done.
	*/
	temp = *pd;
	if(temp.d_best == Three_of_a_kind) {
		no3three(&temp);
		if(temp.d_best == Three_of_a_kind)
			no3deuce(&temp);
	}
	nofives(&temp);
	if(jokermode == True)
		nojokers(&temp);
	if(sameface(&temp, Ace, True) == True) {
		*pd = temp;
		return;
	}

	/*
	**	Try to get all Fives showing.  If we can, we're done.
	*/
	if(need == 0 || need >= FIVE * P_AOKMULT) {
		temp = *pd;
		if(temp.d_best == Three_of_a_kind) {
			no3three(&temp);
			if(temp.d_best == Three_of_a_kind)
				no3deuce(&temp);
		}
		noaces(&temp);
		if(jokermode == True)
			nojokers(&temp);
		if(sameface(&temp, Five, True) == True) {
			*pd = temp;
			return;
		}
	}

	/*
	**	Try to get all Jokers showing.  If we can, we're done.
	*/
	if(jokermode == True) {
		if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
			temp = *pd;
			if(temp.d_best == Three_of_a_kind) {
				no3three(&temp);
				if(temp.d_best == Three_of_a_kind)
					no3deuce(&temp);
			}
			noaces(&temp);
			nofives(&temp);
			if(sameface(&temp, Joker, True) == True) {
				*pd = temp;
				return;
			}
		}
	}

	/*
	**	Discard Jokers and Fives.
	**	Discard Aces if the result is three or more dice.
	*/
	if(jokermode == True)
		nojokers(pd);
	nofives(pd);
	temp = *pd;
	noaces(&temp);
	if(temp.d_rolling >= THREE)
		*pd = temp;
}

/*
**	picky: be picky about what we'll keep
*/
static
picky(pd, need)
diceset	   *pd;
int			need;
{
	diceset	temp;

	/*
	**	Respect a completed dice set.
	*/
	if(pd->d_rolling == 0)
		return;

	/*
	**	Don't like 3o'kind in twos or threes.
	*/
	if(pd->d_best == Three_of_a_kind) {
		if(need == 0 || need > THREE * P_3OKMULT) {
			no3three(pd);
			if(pd->d_best == Three_of_a_kind)
				if(need == 0 || need > DEUCE * P_3OKMULT)
					no3deuce(pd);
		}
	}

	/*
	**	We've got held Aces, discard Jokers and Fives.
	**	If not all Aces showing, discard Aces too.
	*/
	if(need == 0 || need >= P_ACEMULT * P_AOKMULT) {
		if(sameface(pd, Ace, False) == True) {
			if(jokermode == True)
				nojokers(pd);
			nofives(pd);
			if(sameface(pd, Ace, True) == False)
				noaces(pd);
			return;
		}
	}
	
	/*
	**	We've got held Fives, discard Jokers and Aces.
	**	If not all Fives showing, discard Fives too.
	*/
	if(need == 0 || need >= FIVE * P_AOKMULT) {
		if(sameface(pd, Five, False) == True) {
			if(jokermode == True)
				nojokers(pd);
			noaces(pd);
			if(sameface(pd, Five, True) == False)
				nofives(pd);
			return;
		}
	}

	/*
	**	We've got held Jokers, discard Fives and Aces.
	**	If not all Jokers showing, discard Jokers too.
	*/
	if(jokermode == True) {
		if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
			if(sameface(pd, Joker, False) == True) {
				nofives(pd);
				noaces(pd);
				if(sameface(pd, Joker, True) == False)
					nojokers(pd);
				return;
			}
		}
	}
	
	/*
	**	We're holding a mix or nothing.  Discard Jokers.
	**	Discard Fives and Aces if the result is three or more dice.
	*/
	if(jokermode == True)
		nojokers(pd);
	temp = *pd;
	nofives(&temp);
	noaces(&temp);
	if(temp.d_rolling >= THREE)
		*pd = temp;
}

/*
**	finicky: a pickier picky
*/
static
finicky(pd, need)
diceset	   *pd;
int			need;
{
	diceset	temp;

	/*
	**	Respect a completed set of dice.
	*/
	if(pd->d_rolling == 0)
		return;

	/*
	**	Discard three twos and Small_straights containing an Ace.
	*/
	if(pd->d_best == Three_of_a_kind)
		if(need == 0 || need > DEUCE * P_3OKMULT)
			no3deuce(pd);
	if(pd->d_best == Small_straight)
		if(need == 0 || need > P_SMSTR)
			noacesmall(pd);
	
	/*
	**	We've held all Aces.  Discard Jokers and Fives.
	**	If rolling more than one die, discard Aces too.
	*/
	if(sameface(pd, Ace, False) == True) {
		if(jokermode == True)
			nojokers(pd);
		nofives(pd);
		if(pd->d_rolling > 1)
			noaces(pd);
		return;
	}
	
	/*
	**	We've held all Fives.  Discard Jokers and Aces.
	**	If rolling more than one die, discard Fives too.
	*/
	if(need == 0 || need >= FIVE * P_AOKMULT) {
		if(sameface(pd, Five, False) == True) {
			if(jokermode == True)
				nojokers(pd);
			noaces(pd);
			if(pd->d_rolling > 1)
				nofives(pd);
			return;
		}
	}
	
	/*
	**	We've held all Jokers.  Discard Fives and Aces.
	**	If we're rolling more than one die, discard Jokers too.
	**	Else, if it will give us three dice, discard Jokers.
	*/
	if(jokermode == True) {
		if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
			if(sameface(pd, Joker, False) == True) {
				nofives(pd);
				noaces(pd);
				if(pd->d_rolling > 1)
					nojokers(pd);
				else {
					temp = *pd;
					nojokers(&temp);
					if(temp.d_rolling >= THREE)
						*pd = temp;
				}
				return;
			}
		}
	}
	
	/*
	**	Holding a mix or nothing.  Discard Jokers and Fives.
	**	If we're rolling more than one, discard Aces too.
	**	Else, if we can get three dice, discard Aces.
	**	Else, discard 3o'kind in threes.
	*/
	if(jokermode == True)
		nojokers(pd);
	nofives(pd);
	if(pd->d_rolling > 1)
		noaces(pd);
	else {
		temp = *pd;
		noaces(&temp);
		if(temp.d_rolling >= THREE)
			*pd = temp;
		else if(pd->d_best == Three_of_a_kind)
			no3three(pd);
	}
}

/*
**	holdall: hold all scoring dice
XXX:	Intended for choosy selection only -- not a valid strategy.
*/
static
holdall(pd, need)
diceset	   *pd;
int			need;
{
#ifdef	lint
	pd = pd;
	need = need;
#endif	lint
}

/*
**	tossall: always throw maximum number of dice
XXX:	Intended for choosy selection only -- not a valid strategy.
*/
static
tossall(pd, need)
diceset	   *pd;
int			need;
{
#ifdef	lint
	need = need;
#endif	lint

	/*
	**	Discard Small_straights, all Three_of_a_kinds, Jokers, Fives, and Aces.
	**	We never honor a complete dice set!
	*/
	if(pd->d_best == Small_straight)
		nosmall(pd);
	if(pd->d_best == Three_of_a_kind)
		no3any(pd);
	if(jokermode == True)
		nojokers(pd);
	nofives(pd);
	noaces(pd);
}

/*
**	choosy: try all known strategies then pick the one
**		with the best expectation for this diceset
*/
static
choosy(pd, need)
diceset	   *pd;
int			need;
{
	register int		n, best, maxx;
	diceset				temp;
	static int		   *xtbl	= 0;
	extern int			strategies;
	extern strategy	   *strattbl[];

	if(xtbl == 0) {
		xtbl = (int *)malloc((unsigned)(strategies * sizeof *xtbl));
		if(xtbl == 0) {
			syslog(LOG_WARNING, "choosy: no memory for xtbl");
			fickle(pd, need);	/* emergency backup! */
			return;
		}
	}

	for(n = 0;n < strategies - 1;++n) {	/* fickle is last */
		if(strattbl[n]->s_func == choosy) {
			*(xtbl+n) = -WINSCORE;
			continue;
		}
		temp = *pd;
		(*strattbl[n]->s_func)(&temp, need);
		*(xtbl+n) = expect(&temp);
	}

	maxx = *(xtbl+(best=0));
	for(n = 1;n < strategies - 1;++n)	/* fickle is last */
		if(*(xtbl+n) > maxx)
			maxx = *(xtbl+(best=n));

	(*strattbl[best]->s_func)(pd, need);
}

/*
**	kamelion: should never be called
*/
static
kamelion(pd, need)
diceset	   *pd;
int			need;
{
	syslog(LOG_WARNING, "kamelion strategy called!");
	choosy(pd, need);
}

/*
**	fickle: pick another strategy randomly!
**		intended for proxy players only
*/
static
fickle(pd, need)
diceset	   *pd;
int			need;
{
	int					n;
	extern int			strategies;
	extern strategy	   *strattbl[];

	hesitate(100L, 1000L);
	n = randint(strategies - 1) - 1;	/* this one is last -- don't pick it */
	(*strattbl[n]->s_func)(pd, need);
}

/*
**	strattbl: table listing available strategies
*/

strategy		st_basic	= { basic,		"basic" };
strategy		st_merrier	= { merrier,	"merrier" };
strategy		st_respect	= { respect,	"respect" };
strategy		st_twohater	= { twohater,	"twohater" };
strategy		st_greedy	= { greedy,		"greedy" };
strategy		st_picky	= { picky,		"picky" };
strategy		st_finicky	= { finicky,	"finicky" };
static strategy	st_holdall	= { holdall,	"holdall" };	/* table only */
static strategy	st_tossall	= { tossall,	"tossall" };	/* table only */
strategy		st_choosy	= { choosy,		"choosy" };
strategy		st_fickle	= { fickle,		"fickle" };
strategy		st_kamelion	= { kamelion,	"kamelion" };	/* semi-dummy */

strategy   *strattbl[]	= {
	&st_basic, &st_merrier, &st_respect, &st_twohater,
	&st_greedy, &st_picky, &st_finicky,
	&st_holdall, &st_tossall, &st_choosy,
	&st_fickle		/* st_fickle must be last */
};

int	strategies	= sizeof strattbl / sizeof strattbl[0];