[comp.sources.games] v01i066: roll - automatic dice roller

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