|
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