|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 18796 (0x496c)
Types: TextFile
Names: »dieopts.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Cubes/dieopts.c«
/* 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