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 d

⟦b3be0130e⟧ TextFile

    Length: 18796 (0x496c)
    Types: TextFile
    Names: »dieopts.c«

Derivation

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

TextFile

/*	vi:set sw=4 ts=4: */
#ifndef	lint
static char	sccsid[] = "@(#)dieopts.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	<strings.h>
#include	"cubes.h"

extern boolean	jokermode;

#define	SIDESIZE	(JOKER + 1)	/* enough room for all faces */
#define	JSIDES		(jokermode == True ? JOKER : SIDES)
#define	JFACE(f)	((jokermode == True && (f) == JOKER) ? P_JOKERMULT : (f))
#define	FVALUE(f)	((f) == ACE ? P_ACEMULT : JFACE(f))

/*
**	names: names of die faces, singular and plural
**		Must be filled in to at least max of SIDES and NDICE!
*/
char   *numnames[][2]	= {
	{ "zero",	"zeroes" },
	{ "one",	"ones" },
	{ "two",	"twos" },
	{ "three",	"threes" },
	{ "four",	"fours" },
	{ "five",	"fives" },
	{ "six",	"sixes" },
	{ "seven",	"sevens" },
	{ "eight",	"eights" },
	{ "joker",	"jokers" },
};

/*
**	initdice: initialize dice status
*/
initdice(pd)
register diceset   *pd;
{
	register int	d;

	for(d = 0;d < NDICE;++d) {
		pd->d_stat[d] = Free;		/* rolling this die */
		pd->d_face[d] = BADFACE;	/* impossible value */
		pd->d_comb[d] = Nothing;	/* no combination */
	}
	zapdesc(pd);					/* clear scoring description */
	pd->d_best = Nothing;			/* no combination */
	pd->d_again = True;				/* rolling again */
	pd->d_rolling = NDICE;			/* rolling all dice */
	pd->d_pts_roll = 0;				/* no points rolled */
	pd->d_pts_dice = 0;				/* no points in set */
	pd->d_pts_turn = 0;				/* no points in turn */
	pd->d_pts_max = 0;				/* no max in turn yet */
	pd->d_mesg[0] = '\0';			/* no message */
}

/*
**	pickup: similar to initdice but only does initialization
**		for re-roll of (usually partial) dice set
**
**		non-scoring dice are Freed
**		change Rolled dice to Free
**		set Free dice faces to BADFACE and combs to Nothing
**		change Taken dice to Held
**		set Held dice combs to Previous
**		resets d_rolling, d_best, d_pts_roll, and d_mesg
*/
pickup(pd)
register diceset   *pd;
{
	register int	d;

	zapdesc(pd);
	pd->d_best = Nothing;
	pd->d_again = True;
	pd->d_rolling = 0;
	pd->d_pts_roll = 0;
	pd->d_mesg[0] = '\0';

	for(d = 0;d < NDICE;++d) {
		if(pd->d_comb[d] == Nothing)
			pd->d_stat[d] = Free;
		switch(pd->d_stat[d]) {
		case Rolled:
			pd->d_stat[d] = Free;	/* fall */
		case Free:
			pd->d_face[d] = BADFACE;
			pd->d_comb[d] = Nothing;
			++pd->d_rolling;
			break;
		case Taken:
			pd->d_stat[d] = Held;	/* fall */
		case Held:
			pd->d_comb[d] = Previous;
			break;
		}
	}

	/*
	**	If no dice are free, then free them all.
	*/
	if(pd->d_rolling == 0) {
		for(d = 0;d < NDICE;++d) {
			pd->d_stat[d] = Free;
			pd->d_face[d] = BADFACE;
			pd->d_comb[d] = Nothing;
		}
		pd->d_rolling = NDICE;
		pd->d_pts_dice = 0;
	}
}

/*
**	rolldice: roll free dice
**		sets d_rolling to number of dice rolled
**		sets d_again to False
*/
rolldice(pd)
register diceset   *pd;
{
	register int	d;

	pd->d_again = False;
	zapdesc(pd);
	pd->d_best = Nothing;
	pd->d_rolling = 0;
	for(d = 0;d < NDICE;++d) {
		if(pd->d_stat[d] == Free) {
			pd->d_stat[d] = Rolled;
			pd->d_face[d] = dieroll();
			pd->d_comb[d] = Nothing;
			++pd->d_rolling;
		}
	}
}

/*
**	zapdesc: clear scoring combination description
*/
zapdesc(pd)
diceset	   *pd;
{
#ifdef	DESC
	register int	d;

	for(d = 0;d < NDICE;++d) {
		pd->d_desc[d].sc_comb = Nothing;	/* no combination */
		pd->d_desc[d].sc_num = 0;			/* none of them */
		pd->d_desc[d].sc_face = BADFACE;	/* no face value */
	}
#else	DESC
#ifdef	lint
	pd = pd;
#endif	lint
#endif	DESC
}

/*
**	evaluate: categorize dice marked as Rolled or Taken
*/
evaluate(pd)
register diceset   *pd;
{
	register int	d, s;
#ifdef	DESC
	register int	nc = 0;
#endif	DESC
	int				held, rolled;
	int				rshow[SIDESIZE];
	int				minshow, maxshow;
	int				len, aces, fives, jokers;
	boolean			ok;

	/*
	**	We start with s == 0 to allow accounting for BADFACE.
	*/
	for(s = 0;s <= JSIDES;++s)
		rshow[s] = 0;
		
	pd->d_mesg[0] = '\0';
	pd->d_best = Nothing;
	zapdesc(pd);
	rolled = held = 0;
	for(d = 0;d < NDICE;++d) {
		s = pd->d_face[d];
		switch(pd->d_stat[d]) {
		case Rolled:
		case Taken:
			pd->d_comb[d] = Nothing;
			++rolled, ++rshow[s];
			break;
		case Held:
			pd->d_comb[d] = Previous;
			++held;
			break;
		default:
			pd->d_stat[d] = Free;
			pd->d_comb[d] = Nothing;
			break;
		}
	}

	/*
	**	Check for All_of_a_kind.  All dice count.
	**	Uses all dice.
	*/
	if((rolled + held) == NDICE) {
		s = pd->d_face[0];
		for(d = 1;d < NDICE;++d)
			if(pd->d_face[d] != s)
				break;
		if(d == NDICE) {
			for(d = 0;d < NDICE;++d)
				pd->d_comb[d] = All_of_a_kind;
			pd->d_best = All_of_a_kind;

#ifdef	DESC
			pd->d_desc[nc].sc_comb = All_of_a_kind;
			pd->d_desc[nc].sc_num = 1;
			pd->d_desc[nc].sc_face = pd->d_face[0];
/*			++nc;	/* not needed */
#endif	DESC

			sprintf(pd->d_mesg, "%s of a kind in %s",
				NUMBER(NDICE), FACE(pd->d_face[0], NDICE));
			return;
		}
	}

	/*
	**	Check for Straight.  Only rolled dice count.
	**	Uses all dice.
	*/
	if(rolled == NDICE) {
		if(rshow[BADFACE] != 0)
			ok = False;
		else {
			ok = True, minshow = JSIDES + 1, maxshow = 0;
			for(s = 0;ok == True && s <= JSIDES;++s) {
				switch(rshow[s]) {
				case 1:
					if(s < minshow) minshow = s;
					if(s > maxshow) maxshow = s;
					break;
				case 0:		break;
				default:	ok = False; break;
				}
			}
		}

		if(ok == True && maxshow - minshow == NDICE - 1) {
			for(d = 0;d < NDICE;++d)
				pd->d_comb[d] = Straight;
			pd->d_best = Straight;

#ifdef	DESC
			pd->d_desc[nc].sc_comb = Straight;
			pd->d_desc[nc].sc_num = 1;
/*			++nc;	/* not needed */
#endif	DESC

			strcpy(pd->d_mesg, "a straight");
			return;
		}
	}

#ifdef	ASMSTR
	/*
	**	Check for Assembled Straight.  Held and Rolled dice count.
	**	Uses all dice.
	*/
	if((rolled + held) == NDICE) {
		int		ashow[SIDESIZE];

		/*
		**	We start with s == 0 to allow accounting for BADFACE.
		*/
		for(s = 0;s <= JSIDES;++s)
			ashow[s] = 0;
		for(d = 0;d < NDICE;++d)
			++ashow[pd->d_face[d]];

		if(ashow[BADFACE] != 0)
			ok = False;
		else {
			ok = True, minshow = JSIDES + 1, maxshow = 0;
			for(s = 0;ok == True && s <= JSIDES;++s) {
				switch(ashow[s]) {
				case 1:
					if(s < minshow) minshow = s;
					if(s > maxshow) maxshow = s;
					break;
				case 0:		break;
				default:	ok = False; break;
				}
			}
		}

		if(ok == True && maxshow - minshow == NDICE - 1) {
			for(d = 0;d < NDICE;++d)
				pd->d_comb[d] = Asm_straight;
			pd->d_best = Asm_straight;

#ifdef	DESC
			pd->d_desc[nc].sc_comb = Asm_straight;
			pd->d_desc[nc].sc_num = 1;
	/*			++nc;	/* not needed */
#endif	DESC

			switch(rolled) {
			case ASMSTR-1:	strcpy(pd->d_mesg, "a completed straight"); break;
			case ASMSTR-2:	strcpy(pd->d_mesg, "an inside straight"); break;
			case 1:			strcpy(pd->d_mesg, "an outside straight"); break;
			default: /*?*/	strcpy(pd->d_mesg, "an assembled straight"); break;
			}
			return;
		}
	}
#endif	ASMSTR

#ifdef	FOUR
	/*
	**	Check for Four_of_a_kind.  Only rolled dice count.
	**	Assumes that only one is possible.
	*/
	if(rolled >= FOUR) {
		for(s = 1;s <= JSIDES;++s) {
			while(rshow[s] >= FOUR) {
				maxshow = FOUR;
				for(d = 0;d < NDICE && maxshow > 0;++d) {
					switch(pd->d_stat[d]) {
					case Rolled:
					case Taken:
						if(pd->d_comb[d] == Nothing && pd->d_face[d] == s) {
							pd->d_comb[d] = Four_of_a_kind;
							--rshow[s];
							--maxshow;
						}
						break;
					}
				}

				if(pd->d_best == Nothing)
					pd->d_best = Four_of_a_kind;

#ifdef	DESC
				pd->d_desc[nc].sc_comb = Four_of_a_kind;
				pd->d_desc[nc].sc_num = 1;
				pd->d_desc[nc].sc_face = s;
				++nc;
#endif	DESC

				if((len = strlen(pd->d_mesg)) > 0) {
					strcat(pd->d_mesg, ", ");
					len += 2;
				}
				sprintf(pd->d_mesg + len, "%s of a kind in %s",
					NUMBER(FOUR), FACE(s, FOUR));
			}
		}
	}
#endif	FOUR

#ifdef	SMSTR
	/*
	**	Check for Small_straight.  Only rolled dice count.
	**	Assumes that only one is possible.
	*/
	if(rolled >= NDICE - 1) {
		ok = False;
		if(rshow[BADFACE] == 0) {
			minshow = maxshow = 0;
			for(s = 1;ok == False && s <= JSIDES;++s) {
				switch(rshow[s]) {
				case 1: case 2:
					if(minshow == 0)
						minshow = maxshow = s;
					else if((maxshow = s) - minshow == NDICE - 2)
						ok = True;
					break;
				case 0:		minshow = maxshow = 0; break;
				default:	s = JSIDES; break;
				}
			}
		}

		if(ok == True) {
			for(s = minshow;s <= maxshow;++s) {
				for(ok = True, d = 0;ok == True && d < NDICE;++d) {
					switch(pd->d_stat[d]) {
					case Rolled:
					case Taken:
						if(pd->d_comb[d] == Nothing && pd->d_face[d] == s) {
							pd->d_comb[d] = Small_straight;
							--rshow[s];
							ok = False;	/* got it */
						}
						break;
					}
				}
			}
			if(pd->d_best == Nothing)
				pd->d_best = Small_straight;

#ifdef	DESC
			pd->d_desc[nc].sc_comb = Small_straight;
			pd->d_desc[nc].sc_num = 1;
			++nc;
#endif	DESC

			if(pd->d_mesg[0] != '\0')
				strcat(pd->d_mesg, ", ");
			strcat(pd->d_mesg, "a small straight");
		}
	}
#endif	SMSTR

	/*
	**	Check for Three_of_a_kind.  Only rolled dice count.
	**	Code is supposed to be able to handle more than one
	**	Three_of_a_kind, but is untested with current NDICE val.
	*/
	if(rolled >= THREE) {
		for(s = 1;s <= JSIDES;++s) {
			while(rshow[s] >= THREE) {
				maxshow = THREE;
				for(d = 0;d < NDICE && maxshow > 0;++d) {
					switch(pd->d_stat[d]) {
					case Rolled:
					case Taken:
						if(pd->d_comb[d] == Nothing && pd->d_face[d] == s) {
							pd->d_comb[d] = Three_of_a_kind;
							--rshow[s];
							--maxshow;
						}
						break;
					}
				}

				if(pd->d_best == Nothing)
					pd->d_best = Three_of_a_kind;

#ifdef	DESC
				pd->d_desc[nc].sc_comb = Three_of_a_kind;
				pd->d_desc[nc].sc_num = 1;
				pd->d_desc[nc].sc_face = s;
				++nc;
#endif	DESC

				if((len = strlen(pd->d_mesg)) > 0) {
					strcat(pd->d_mesg, ", ");
					len += 2;
				}
				sprintf(pd->d_mesg + len, "%s of a kind in %s",
					NUMBER(THREE), FACE(s, THREE));
			}
		}
	}

	/*
	**	Check for stray Aces, Fives, and Jokers.  Only rolled dice count.
	*/
	aces = fives = jokers = 0;
	for(d = 0;d < NDICE;++d) {
		switch(pd->d_stat[d]) {
		case Rolled:
		case Taken:
			if(pd->d_comb[d] == Nothing) {
				switch(pd->d_face[d]) {
				case ACE:
					++aces;
					pd->d_comb[d] = Ace;
					if(pd->d_best == Nothing
					|| pd->d_best == Joker || pd->d_best == Five)
						pd->d_best = Ace;
					break;
				case FIVE:
					++fives;
					pd->d_comb[d] = Five;
					if(pd->d_best == Nothing || pd->d_best == Joker)
						pd->d_best = Five;
					break;
				case JOKER:
					/*
					**	The test for jokermode here prevents any Joker
					**	dice being marked, thus it is unnecessary to
					**	test jokermode when testing Joker in other places.
					*/
					if(jokermode == True) {
						++jokers;
						pd->d_comb[d] = Joker;
						if(pd->d_best == Nothing)
							pd->d_best = Joker;
					}
					break;
				}
			}
			break;
		}
	}

	if(pd->d_best != Nothing) {
		if(aces > 0) {
#ifdef	DESC
			pd->d_desc[nc].sc_comb = Ace;
			pd->d_desc[nc].sc_num = aces;
			pd->d_desc[nc].sc_face = ACE;
			++nc;
#endif	DESC
			if((len = strlen(pd->d_mesg)) > 0) {
				strcat(pd->d_mesg, ", ");
				len += 2;
			}
			sprintf(pd->d_mesg + len, "%s %s",
				NUMBER(aces), FACE(ACE, aces));
		}

		if(fives > 0) {
#ifdef	DESC
			pd->d_desc[nc].sc_comb = Five;
			pd->d_desc[nc].sc_num = fives;
			pd->d_desc[nc].sc_face = FIVE;
			++nc;
#endif	DESC
			if((len = strlen(pd->d_mesg)) > 0) {
				strcat(pd->d_mesg, ", ");
				len += 2;
			}
			sprintf(pd->d_mesg + len, "%s %s",
				NUMBER(fives), FACE(FIVE, fives));
		}

		if(jokermode == True && jokers > 0) {
#ifdef	DESC
			pd->d_desc[nc].sc_comb = Joker;
			pd->d_desc[nc].sc_num = jokers;
			pd->d_desc[nc].sc_face = JOKER;
			++nc;
#endif	DESC
			if((len = strlen(pd->d_mesg)) > 0) {
				strcat(pd->d_mesg, ", ");
				len += 2;
			}
			sprintf(pd->d_mesg + len, "%s %s",
				NUMBER(jokers), FACE(JOKER, jokers));
		}
	}

	if(pd->d_best == Nothing) {
		strcpy(pd->d_mesg, "nothing");
#ifdef	DESC
		pd->d_desc[nc].sc_num = 1;	/* to be strictly accurate */
/*		++nc;						/* not needed */
#endif	DESC
	}
}

/*
**	keepall: mark all scoring dice (based on combinations) as Taken
**		frees Nothing dice and marks as Held Previous dice
**		sets d_rolling to number of Free dice
**		does not alter d_again or d_pts_????
*/
keepall(pd)
register diceset   *pd;
{
	register int	d;

	pd->d_rolling = 0;
	for(d = 0;d < NDICE;++d) {
		switch(pd->d_comb[d]) {
		case Previous:
			pd->d_stat[d] = Held;
			break;
		case Nothing:
			pd->d_stat[d] = Free;
			++pd->d_rolling;
			break;
		case All_of_a_kind:
		case Asm_straight:
			if(pd->d_stat[d] != Held)
				pd->d_stat[d] = Taken;
			break;
		default:
			pd->d_stat[d] = Taken;
			break;
		}
	}
}

/*
**	freeall: mark all non-held dice (based on combinations) as Free
**		sets d_rolling to number of Free dice
**		does not alter d_again or d_pts_????
*/
freeall(pd)
register diceset   *pd;
{
	register int	d;

	pd->d_rolling = 0;
	for(d = 0;d < NDICE;++d) {
		switch(pd->d_comb[d]) {
		case Previous:
			pd->d_stat[d] = Held;
			break;
		default:
			pd->d_stat[d] = Free;
			++pd->d_rolling;
			break;
		}
	}
}

/*
**	scoredice: update points values after roll and decision
*/
scoredice(pd)
register diceset   *pd;
{
	register int	d, dd, n;
	register int	points;
	int				face;
	combination		comb[NDICE];

	/*
	**	The easiest of all is the Nothing combination.  The points for the roll
	**	are the negative of the points accumulated so far in this turn.  We
	**	leave d_pts_max alone -- signifying the true loss due to the reroll.
	*/
	if(pd->d_best == Nothing) {
		pd->d_pts_roll = -pd->d_pts_turn;
		pd->d_pts_dice = pd->d_pts_turn = 0;
/*		pd->d_pts_max = pd->d_pts_max;			/* leave alone */
		return;
	}

	/*
	**	All_of_a_kind can occur at any time and changes the value of any saved
	**	dice.  The value of d_pts_dice must be used to update d_pts_roll,
	**	d_pts_turn, and d_pts_max.  Further, the value of All_of_a_kind depends
	**	on its denomination.
	*/
	if(pd->d_best == All_of_a_kind) {
		face = pd->d_face[0];
		points = P_AOKMULT * FVALUE(face);
		pd->d_pts_roll = points - pd->d_pts_dice;
		if((pd->d_pts_turn += pd->d_pts_roll) > pd->d_pts_max)
			pd->d_pts_max = pd->d_pts_turn;
		return;
	}

	/*
	**	A Straight can occur only when all dice are being rolled, so d_pts_roll
	**	and d_pts_dice should be zero.  The value of a Straight is a constant.
	*/
	if(pd->d_best == Straight) {
		points = P_STRAIGHT;
		pd->d_pts_roll = points;
		pd->d_pts_dice = points;
		if((pd->d_pts_turn += points) > pd->d_pts_max)
			pd->d_pts_max = pd->d_pts_turn;
		return;
	}

#ifdef	ASMSTR
	/*
	**	An Asm_straight can occur only when there were previously held dice.
	**	As with All_of_a_kind, the value of the saved dice is altered.
	**	This combination uses all dice and its value is a constant.
	*/
	if(pd->d_best == Asm_straight) {
		points = P_ASMSTR;
		pd->d_pts_roll = points - pd->d_pts_dice;
		if((pd->d_pts_turn += pd->d_pts_roll) > pd->d_pts_max)
			pd->d_pts_max = pd->d_pts_turn;
		return;
	}
#endif	ASMSTR

	/*
	**	The rest of the combinations can occur in concert.
	*/
	pd->d_pts_roll = 0;

#ifdef	FOUR
	/*
	**	Four_of_a_kind is tricky. The value is dependent on the denomination,
	**	but not all dice are used up.  Even worse, for the sake of generality,
	**	we must assume that there could be more than one Four_of_a_kind.
	**	This code assumes that Four_of_a_kind and Small_straight will
	**	not occur at the same time.
	*/
	if(pd->d_best == Four_of_a_kind) {
		for(d = 0;d < NDICE;++d)
			comb[d] = pd->d_comb[d];
		for(d = 0;d < NDICE;++d) {
			if(comb[d] == Four_of_a_kind) {
				/*
				**	Award the points for this one.
				*/
				face = pd->d_face[d];
				points = P_4OKMULT * FVALUE(face);
				pd->d_pts_roll += points;
				pd->d_pts_dice += points;
				if((pd->d_pts_turn += points) > pd->d_pts_max)
					pd->d_pts_max = pd->d_pts_turn;

				/*
				**	Obliterate the scoring dice.
				*/
				for(n = FOUR, dd = d;dd < NDICE;++dd) {
					if(comb[dd] != Four_of_a_kind)
						continue;
					if(pd->d_face[dd] != face)
						continue;
					comb[dd] = Nothing;
					if(--n == 0)
						break;
				}
			}
		}
	}
#endif	FOUR

#ifdef	SMSTR
	/*
	**	Score a Small_straight.  This code assumes that Four_of_a_kind
	**	(or Three_of_a_kind) and Small_straight will not occur at the
	**	same time.  It also assumes that only one Small_straight can
	**	occur at a time.
	*/
	if(pd->d_best == Small_straight) {
		points = P_SMSTR;
		pd->d_pts_roll += points;
		pd->d_pts_dice += points;
		if((pd->d_pts_turn += points) > pd->d_pts_max)
			pd->d_pts_max = pd->d_pts_turn;
	}
#endif	SMSTR

	/*
	**	Three_of_a_kind is tricky. The value is dependent on the denomination,
	**	but not all dice are used up.  Even worse, for the sake of generality,
	**	we must assume that there could be more than one Three_of_a_kind.
	**	Assumes that Three_of_a_kind does not occur in conjunction with
	**	Four_of_a_kind or Small_straight.
	*/
	if(pd->d_best == Three_of_a_kind) {
		for(d = 0;d < NDICE;++d)
			comb[d] = pd->d_comb[d];
		for(d = 0;d < NDICE;++d) {
			if(comb[d] == Three_of_a_kind) {
				/*
				**	Award the points for this one.
				*/
				face = pd->d_face[d];
				points = P_3OKMULT * FVALUE(face);
				pd->d_pts_roll += points;
				pd->d_pts_dice += points;
				if((pd->d_pts_turn += points) > pd->d_pts_max)
					pd->d_pts_max = pd->d_pts_turn;

				/*
				**	Obliterate the scoring dice.
				*/
				for(n = THREE, dd = d;dd < NDICE;++dd) {
					if(comb[dd] != Three_of_a_kind)
						continue;
					if(pd->d_face[dd] != face)
						continue;
					comb[dd] = Nothing;
					if(--n == 0)
						break;
				}
			}
		}
	}

	/*
	**	Finally we have Aces, Fives and Jokers.  Easy.
	*/
	for(d = 0;d < NDICE;++d) {
		switch(pd->d_comb[d]) {
		case Joker:	points = P_JOKER; goto addscore;
		case Five:	points = P_FIVE; goto addscore;
		case Ace:	points = P_ACE; goto addscore;
addscore:
			pd->d_pts_roll += points;
			pd->d_pts_dice += points;
			if((pd->d_pts_turn += points) > pd->d_pts_max)
				pd->d_pts_max = pd->d_pts_turn;
			break;
		default:
			break;
		}
	}
}

#ifdef	ASMSTR
/*
**	heldsmall: if Small_straight held, return lowest face, else BADFACE
*/
heldsmall(pd)
diceset	   *pd;
{
	register int	d, low;
	diceset			temp;

	if(pd->d_rolling != 1)
		return BADFACE;
	
	/*
	**	Pretend like we just rolled this hand then evaluate it.
	*/
	temp = *pd;
	for(d = 0;d < NDICE;++d)
		temp.d_stat[d] = Rolled;
	evaluate(&temp);
	if(temp.d_best != Small_straight)
		return BADFACE;
	
	/*
	**	Find lowest face in the Small_straight.
	*/
	low = JOKER+1;
	for(d = 0;d < NDICE;++d)
		if(temp.d_comb[d] == Small_straight && temp.d_face[d] < low)
			low = temp.d_face[d];
	
	return low;
}
#endif	ASMSTR