home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume1
/
roll
/
roll.c
< prev
Wrap
C/C++ Source or Header
|
1987-06-29
|
7KB
|
294 lines
/*****************************************************************************
* ROLL - Rolls dice - lots of them - and really randomly.
*
*
* Usage: (options included in braces):
*
* roll {numrep@}{{bestroll,}numroll x}{{bestdice,}numdice d}{sides}
*
* numrep [1] = number of times to repeat the rolling sequence.
* bestroll [numroll] = print the best "bestroll" rolls.
* numroll [1] = number of rolls to do.
* bestdice [numdice] = use the "bestdice" highest rolling dice.
* numdice [1] = number of dice to use per roll.
* sides [100] = number of sides on the dice.
*
* Examples:
* roll
* d100 = 65
* roll 6
* d6 = 3
* roll 4d10
* 4d10 = 11
* roll 5,10d8
* 5,10d8 = 28
* roll 6x3d6
* 6x3d6 = 17 12 11 11 10 6
* roll 6x3,4d6
* 6x3,4d6 = 18 15 10 10 7 6
* roll 5,10x4d4
* 5,10x4d4 = 14 13 12 12 10
* roll 3@6,10x3,4d6
* 6,10x3,4d6 = 17 17 15 15 14 14
* 6,10x3,4d6 = 18 15 15 15 14 14
* 6,10x3,4d6 = 16 14 13 13 11 11
******************************************************************************/
#include <stdio.h>
#include <ctype.h>
#define NUMREDUX 5
#ifdef SYSV
#define index strchr
#define rindex strrchr
#define srandom srand
#define random rand
#endif
extern char *index(), *rindex();
extern char *malloc();
extern void free();
int numroll = 1, bestroll = 1; /* Number of rolls to roll and keep */
int numdice = 1, bestdice = 1; /* Number of dice to roll and keep */
int sides = 100; /* Number of sides on each die */
int *ar_rolls; /* Array of rolls */
int *ar_dice; /* Array of dice */
int *ar_side; /* Array of side data */
char *show(); /* Routine to format output */
char iline[80]; /* To parse the roll */
char aroll[80]; /* When rolls are repeated */
main(acnt,avar)
int acnt;
char *avar[];
{
int i, j, k, val;
char *s, *s1;
/* if(acnt < 2){
printf("usage: roll {numroll x }{numdice d }{numsides}\n");
printf("\tExample: roll 100 ; roll 3d8 ; roll 6x3d8\n");
return;
}
*/
srandom(time(0L)); /* Randomize */
if(acnt <= 1) /* Default: Roll 1d100 */
roll("");
else
for(i=0; ++i < acnt;){ /* For each argument */
s = avar[i];
if(s1 = index(s,'@')){ /* Repeat the roll? */
*s1 = 0;
j = atoi(s); /* Get repetition */
if(j < 1){
printf("roll: Repetition count must be greater than zero.\n");
return;
}
s = s1+1; /* Advance pointer past it */
}
else j = 1; /* Default: Only one time. */
strcpy(aroll,s); /* Save it. */
while(j--){
strcpy(s,aroll);
roll(s); /* Do the roll */
}
}
}
roll(inline)
char *inline;
{
int i, j, k, val, r;
char *s, *s1;
numroll = bestroll = bestdice = numdice = 1; /* Set defaults. */
sides = 100;
for(s=inline; *s; ++s) /* Convert to lower case */
if(isupper(*s))
*s = tolower(*s);
s = inline;
if(s1 = index(s,'x')){ /* Get number of rolls */
*s1 = 0;
parse(s,&numroll,&bestroll);
s = s1+1;
}
if(s1 = index(s,'d')){ /* Get number of dice */
*s1 = 0;
parse(s,&numdice,&bestdice);
s = s1+1;
}
if(*s) sides = atoi(s); /* get number of sides */
if(error()) return; /* Check sanity */
if(numroll > 1) printf("%sx",show(iline,bestroll,numroll));
if(numdice > 1) printf("%s",show(iline,bestdice,numdice));
printf("d%d = ",sides);
fflush(stdout); /* Echo the command */
/* Allocate the arrays - one to keep all the rolls, one to keep each roll
by the die roll, and one to make sure the dice are rolled RANDOMLY.
*/
ar_rolls = (int *)malloc(sizeof(int) * numroll);
ar_dice = (int *)malloc(sizeof(int) * numdice);
ar_side = (int *)malloc(sizeof(int) * NUMREDUX * sides);
/* Get out if we couldn't allocate the arrays */
if(!ar_rolls || !ar_dice || !ar_side){
printf("*** Out of memory ***\n");
if(ar_rolls) free(ar_rolls);
if(ar_dice) free(ar_dice);
if(ar_side) free(ar_side);
return;
}
/* Make an array filled with the possible side values. Several times. So
that even if the random number generator isn't completely random, it
has a chance to produce random values when indexing into the array.
*/
for(i=j=0; i<NUMREDUX; ++i)
for(k=0; k++ < sides; ++j)
*(ar_side+j) = k;
/* Randomize the array - necessary to catch cyclic random number generators. */
for(i=0; i < NUMREDUX * sides; ++i){
r = random();
if(r < 0) r = -r;
r %= NUMREDUX * sides;
j = *(ar_side+i);
*(ar_side+i) = *(ar_side+r);
*(ar_side+r) = j;
}
for(i = 0; i<numroll; ++i){ /* For each roll */
for(j=0; j<numdice; ++j){ /* For each die */
r = random(); /* Roll the die */
if(r < 0) r = -r;
*(ar_dice+j) = *(ar_side + (r % (sides * NUMREDUX)));
}
if(bestdice < numdice) sort(ar_dice,numdice); /* Get the best 'n' */
for(j=val=0; j<bestdice; ++j) /* Sum them to get the roll */
val += *(ar_dice+j);
*(ar_rolls+i) = val;
}
sort(ar_rolls,numroll); /* Sort the rolls */
for(i=0; i<bestroll; ++i) /* And print out the best 'n' */
printf("%d ",*(ar_rolls+i));
printf("\n");
free(ar_rolls); /* Free all the arrays */
free(ar_dice);
free(ar_side);
}
/*****************************************************************************
* PARSE
*
* Figure out strings that look like "ddd" and "ddd,ddd", and fill in
* the values nicely. Handle defaults, too.
******************************************************************************/
parse(s,n,b)
char *s;
int *n, *b;
{
char *s1;
if(s1 = index(s,',')){
*s1 = 0;
*b = atoi(s);
*n = atoi(s1+1);
}
else *b = *n = atoi(s);
}
/*****************************************************************************
* SORT
*
* Bubble sort (yech) an array.
******************************************************************************/
sort(a,n)
int a[], n;
{
int changed, i, t;
if(n <= 1) return;
for(changed=1; changed;){
changed = 0;
for(i=0; i<n-1; ++i){
if(a[i] < a[i+1]){
changed = 1;
t = a[i]; a[i] = a[i+1]; a[i+1] = t;
}
}
}
}
/*****************************************************************************
* ERROR
*
* Scan and report any errors.
******************************************************************************/
error(){
int iserr=0;
if(numroll <= 0){
fprintf(stderr,"roll: Number of rolls must be greater than zero.\n");
++iserr;
}
if(bestroll < 1 || bestroll > numroll){
fprintf(stderr,"roll: Number of rolls to keep must be greater than zero,\n");
fprintf(stderr," less than the total number of rolls.\n");
++iserr;
}
if(numdice <= 0){
fprintf(stderr,"roll: Number of dice to roll must be greater than zero.\n");
++iserr;
}
if(bestdice < 1 || bestdice > numdice){
fprintf(stderr,"roll: Number of dice to keep must be greater than zero,\n");
fprintf(stderr," less than the number of dice.\n");
++iserr;
}
if(sides <= 1){
fprintf(stderr,"roll: Dice must have at least two sides.\n");
++iserr;
}
return(iserr);
}
/*****************************************************************************
* SHOW
*
* Format some output.
******************************************************************************/
char *show(s,b,n)
char *s;
int b, n;
{
if(b == n)
sprintf(s,"%d",n);
else
sprintf(s,"%d,%d",b,n);
return(s);
}