games-request@tekred.TEK.COM (06/30/87)
Submitted by: Bruce Holloway <drivax!holloway@ames.arpa>
Comp.sources.games: Volume 1, Issue 66
Archive-name: roll
[I haven't tried this, so you're on your own. -br]
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: README Makefile roll.c
# Wrapped by billr@tekred on Mon Jun 29 16:37:32 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(985 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThe Ultimate Dice Roller! Should be transportable to most systems that
Xcan run 'C' and have the standard library.
X
XThis dice roller is random, even if the random number generator isn't very
Xrandom.
X
XUsage: (options included in braces):
X
Xroll {numrep@}{{bestroll,}numroll x}{{bestdice,}numdice d}{sides}
X
Xnumrep [1] = number of times to repeat the rolling sequence.
Xbestroll [numroll] = print the best "bestroll" rolls.
Xnumroll [1] = number of rolls to do.
Xbestdice [numdice] = use the "bestdice" highest rolling dice.
Xnumdice [1] = number of dice to use per roll.
Xsides [100] = number of sides on the dice.
X
XExamples:
X roll
X d100 = 65
X roll 6
X d6 = 3
X roll 4d10
X 4d10 = 11
X roll 5,10d8
X 5,10d8 = 28
X roll 6x3d6
X 6x3d6 = 17 12 11 11 10 6
X roll 6x3,4d6
X 6x3,4d6 = 18 15 10 10 7 6
X roll 5,10x4d4
X 5,10x4d4 = 14 13 12 12 10
X roll 3@6,10x3,4d6
X 6,10x3,4d6 = 17 17 15 15 14 14
X 6,10x3,4d6 = 18 15 15 15 14 14
X 6,10x3,4d6 = 16 14 13 13 11 11
X
END_OF_README
if test 985 -ne `wc -c <README`; then
echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(229 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# Makefile for ROLL
X#
X# Comment out the BSD line if you're on System V
X# Comment out the SYSV line if you're using Berkely Unix.
X
X# SYSTEM = -DSYSV
XSYSTEM = -DBSD
X
XCFLAGS = -O $(SYSTEM)
X
Xroll: roll.c
X cc -o roll $(CFLAGS) roll.c
END_OF_Makefile
if test 229 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f roll.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"roll.c\"
else
echo shar: Extracting \"roll.c\" \(7305 characters\)
sed "s/^X//" >roll.c <<'END_OF_roll.c'
X/*****************************************************************************
X* ROLL - Rolls dice - lots of them - and really randomly.
X*
X*
X* Usage: (options included in braces):
X*
X* roll {numrep@}{{bestroll,}numroll x}{{bestdice,}numdice d}{sides}
X*
X* numrep [1] = number of times to repeat the rolling sequence.
X* bestroll [numroll] = print the best "bestroll" rolls.
X* numroll [1] = number of rolls to do.
X* bestdice [numdice] = use the "bestdice" highest rolling dice.
X* numdice [1] = number of dice to use per roll.
X* sides [100] = number of sides on the dice.
X*
X* Examples:
X* roll
X* d100 = 65
X* roll 6
X* d6 = 3
X* roll 4d10
X* 4d10 = 11
X* roll 5,10d8
X* 5,10d8 = 28
X* roll 6x3d6
X* 6x3d6 = 17 12 11 11 10 6
X* roll 6x3,4d6
X* 6x3,4d6 = 18 15 10 10 7 6
X* roll 5,10x4d4
X* 5,10x4d4 = 14 13 12 12 10
X* roll 3@6,10x3,4d6
X* 6,10x3,4d6 = 17 17 15 15 14 14
X* 6,10x3,4d6 = 18 15 15 15 14 14
X* 6,10x3,4d6 = 16 14 13 13 11 11
X******************************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#define NUMREDUX 5
X
X#ifdef SYSV
X#define index strchr
X#define rindex strrchr
X#define srandom srand
X#define random rand
X#endif
X
Xextern char *index(), *rindex();
Xextern char *malloc();
Xextern void free();
X
Xint numroll = 1, bestroll = 1; /* Number of rolls to roll and keep */
Xint numdice = 1, bestdice = 1; /* Number of dice to roll and keep */
Xint sides = 100; /* Number of sides on each die */
X
Xint *ar_rolls; /* Array of rolls */
Xint *ar_dice; /* Array of dice */
Xint *ar_side; /* Array of side data */
X
Xchar *show(); /* Routine to format output */
X
Xchar iline[80]; /* To parse the roll */
Xchar aroll[80]; /* When rolls are repeated */
X
Xmain(acnt,avar)
Xint acnt;
Xchar *avar[];
X{
X int i, j, k, val;
X char *s, *s1;
X
X/* if(acnt < 2){
X printf("usage: roll {numroll x }{numdice d }{numsides}\n");
X printf("\tExample: roll 100 ; roll 3d8 ; roll 6x3d8\n");
X return;
X }
X*/
X srandom(time(0L)); /* Randomize */
X
X if(acnt <= 1) /* Default: Roll 1d100 */
X roll("");
X else
X for(i=0; ++i < acnt;){ /* For each argument */
X s = avar[i];
X if(s1 = index(s,'@')){ /* Repeat the roll? */
X *s1 = 0;
X j = atoi(s); /* Get repetition */
X if(j < 1){
X printf("roll: Repetition count must be greater than zero.\n");
X return;
X }
X s = s1+1; /* Advance pointer past it */
X }
X else j = 1; /* Default: Only one time. */
X strcpy(aroll,s); /* Save it. */
X while(j--){
X strcpy(s,aroll);
X roll(s); /* Do the roll */
X }
X }
X}
X
Xroll(inline)
Xchar *inline;
X{
X int i, j, k, val, r;
X char *s, *s1;
X
X numroll = bestroll = bestdice = numdice = 1; /* Set defaults. */
X sides = 100;
X
X for(s=inline; *s; ++s) /* Convert to lower case */
X if(isupper(*s))
X *s = tolower(*s);
X
X s = inline;
X if(s1 = index(s,'x')){ /* Get number of rolls */
X *s1 = 0;
X parse(s,&numroll,&bestroll);
X s = s1+1;
X }
X if(s1 = index(s,'d')){ /* Get number of dice */
X *s1 = 0;
X parse(s,&numdice,&bestdice);
X s = s1+1;
X }
X if(*s) sides = atoi(s); /* get number of sides */
X
X if(error()) return; /* Check sanity */
X
X if(numroll > 1) printf("%sx",show(iline,bestroll,numroll));
X if(numdice > 1) printf("%s",show(iline,bestdice,numdice));
X printf("d%d = ",sides);
X fflush(stdout); /* Echo the command */
X
X/* Allocate the arrays - one to keep all the rolls, one to keep each roll
X by the die roll, and one to make sure the dice are rolled RANDOMLY.
X*/
X ar_rolls = (int *)malloc(sizeof(int) * numroll);
X ar_dice = (int *)malloc(sizeof(int) * numdice);
X ar_side = (int *)malloc(sizeof(int) * NUMREDUX * sides);
X
X/* Get out if we couldn't allocate the arrays */
X
X if(!ar_rolls || !ar_dice || !ar_side){
X printf("*** Out of memory ***\n");
X if(ar_rolls) free(ar_rolls);
X if(ar_dice) free(ar_dice);
X if(ar_side) free(ar_side);
X return;
X }
X
X/* Make an array filled with the possible side values. Several times. So
X that even if the random number generator isn't completely random, it
X has a chance to produce random values when indexing into the array.
X*/
X for(i=j=0; i<NUMREDUX; ++i)
X for(k=0; k++ < sides; ++j)
X *(ar_side+j) = k;
X
X/* Randomize the array - necessary to catch cyclic random number generators. */
X
X for(i=0; i < NUMREDUX * sides; ++i){
X r = random();
X if(r < 0) r = -r;
X r %= NUMREDUX * sides;
X j = *(ar_side+i);
X *(ar_side+i) = *(ar_side+r);
X *(ar_side+r) = j;
X }
X
X for(i = 0; i<numroll; ++i){ /* For each roll */
X for(j=0; j<numdice; ++j){ /* For each die */
X r = random(); /* Roll the die */
X if(r < 0) r = -r;
X *(ar_dice+j) = *(ar_side + (r % (sides * NUMREDUX)));
X }
X if(bestdice < numdice) sort(ar_dice,numdice); /* Get the best 'n' */
X for(j=val=0; j<bestdice; ++j) /* Sum them to get the roll */
X val += *(ar_dice+j);
X *(ar_rolls+i) = val;
X }
X sort(ar_rolls,numroll); /* Sort the rolls */
X for(i=0; i<bestroll; ++i) /* And print out the best 'n' */
X printf("%d ",*(ar_rolls+i));
X printf("\n");
X
X free(ar_rolls); /* Free all the arrays */
X free(ar_dice);
X free(ar_side);
X}
X
X/*****************************************************************************
X* PARSE
X*
X* Figure out strings that look like "ddd" and "ddd,ddd", and fill in
X* the values nicely. Handle defaults, too.
X******************************************************************************/
X
Xparse(s,n,b)
Xchar *s;
Xint *n, *b;
X{
X char *s1;
X
X if(s1 = index(s,',')){
X *s1 = 0;
X *b = atoi(s);
X *n = atoi(s1+1);
X }
X else *b = *n = atoi(s);
X}
X
X/*****************************************************************************
X* SORT
X*
X* Bubble sort (yech) an array.
X******************************************************************************/
X
Xsort(a,n)
Xint a[], n;
X{
X int changed, i, t;
X
X if(n <= 1) return;
X
X for(changed=1; changed;){
X changed = 0;
X for(i=0; i<n-1; ++i){
X if(a[i] < a[i+1]){
X changed = 1;
X t = a[i]; a[i] = a[i+1]; a[i+1] = t;
X }
X }
X }
X}
X
X/*****************************************************************************
X* ERROR
X*
X* Scan and report any errors.
X******************************************************************************/
X
Xerror(){
X int iserr=0;
X
X if(numroll <= 0){
X fprintf(stderr,"roll: Number of rolls must be greater than zero.\n");
X ++iserr;
X }
X
X if(bestroll < 1 || bestroll > numroll){
X fprintf(stderr,"roll: Number of rolls to keep must be greater than zero,\n");
X fprintf(stderr," less than the total number of rolls.\n");
X ++iserr;
X }
X
X if(numdice <= 0){
X fprintf(stderr,"roll: Number of dice to roll must be greater than zero.\n");
X ++iserr;
X }
X
X if(bestdice < 1 || bestdice > numdice){
X fprintf(stderr,"roll: Number of dice to keep must be greater than zero,\n");
X fprintf(stderr," less than the number of dice.\n");
X ++iserr;
X }
X
X if(sides <= 1){
X fprintf(stderr,"roll: Dice must have at least two sides.\n");
X ++iserr;
X }
X
X return(iserr);
X}
X
X/*****************************************************************************
X* SHOW
X*
X* Format some output.
X******************************************************************************/
X
Xchar *show(s,b,n)
Xchar *s;
Xint b, n;
X{
X if(b == n)
X sprintf(s,"%d",n);
X else
X sprintf(s,"%d,%d",b,n);
X return(s);
X}
END_OF_roll.c
if test 7305 -ne `wc -c <roll.c`; then
echo shar: \"roll.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0