/* *************************************************************************** * * * Dice Simulator v1.2 Release Date: 08/21/00 * * * * A handy, dandy dice simulation program brought to you by * * Edward Glamkowski. * * * * This program was originally written on an AMD K6 running Win98 using * * the Microsoft Visual C++ 6.0 Standard Edition compiler. I make no * * guarentees about portability, but it is such a trivial, straightforward * * program there shouldn't be any serious issues, if even any at all. * * * * Just run the executable with no arguments to get help, or better yet, * * read the code to see how it works! Please read the code anyway, as * * there are a few issues (concerning seeding the random number generator * * and the 'i' option for large die sizes, specifically) of which you * * should be aware. You may also want to see if the random number * * generator is satisfactory - I would love to know if you have a better * * one! * * * * This program is freeware (it's too trivial to be anything else!), * * though an email would be appreciated if you decide to use it more * * than once. * * * * Any comments, questions or bug reports can be sent to me at * * eglamkowski@angelfire.com * * * * HISTORY: * * v1.0 08/20/00: Initial release * * v1.1 08/21/00: Send error messages to stderr instead of stdout. Duh. * * Windows users won't notice a difference, but UNIX users * * should greatly appreciate this change. * * v1.2 08/21/00: To avoid problems with bad seeds of the random number * * generator, I put in my own sleep function (sleep() isn't * * ANSI, and I don't want to have to bother checking for * * it, so I'm just blanket including and using my own) for * * so I never get the same time back twice. * * * *************************************************************************** */ #include #include #include #include /* Function prototypes */ void sleep_ms(clock_t wait); int dice(int number, int size); int rand(void); void hseed(long seed); /* Pauses for a specified number of milliseconds. */ void sleep_ms(clock_t wait) { clock_t goal = wait + clock(); while (goal > clock()) ; } /* simulates dice rolls */ int dice(int number, int size) { int sum = 0; if (size <= 0 || number <= 0) return (0); while (number-- > 0) sum += ((rand() % size) + 1); return (sum); } int main(int argc, char **argv) { int num; /* Number of dice to be rolled. */ int size; /* Size of the dice to be rolled. */ int total = 0; /* Total of all the dice rolled. */ int one_die; /* Result of rolling one die. */ int cnt = 0; /* Just a small little counter. */ int line_len; /* Length of the output line. */ int *individual_rolls = NULL; /* For 'i' and 'b' display modes. */ int show_tab = 0, show_ind = 0, show_tot = 0; /* Display modes. */ long s; /* Seed for the random number generator. */ char mode = 't'; /* How to display the results. */ char buf[8192]; buf[0] = '\0'; /* For printing out the final results. */ /* * Seed our random number generator. We need to sleep for 1 second * to make sure we don't get back the same seed if it program is * run many times in quick succession. */ printf("\r\nSeeding random number generator, please wait...\r\n"); sleep_ms(1000); s = time(0); hseed(s); /* ****************************************************************** * * * Parse our arguments and figure out what die we're rolling, how * * many times, and how we want the results displayed. * * * ****************************************************************** */ if (argc < 3 || argc > 4) { printf("\r\nUsage: [t|i|b]\r\n\r\n"); printf("t (Total only) = just show the final total (DEFAULT)\r\n"); printf("i (Individual) = show each individual die roll\r\n"); printf("b (taBulation) = show number of rolls for each pip\r\n"); exit(1); } num = atoi(argv[1]); size = atoi(argv[2]); if (num < 1 || size < 1) { /* Can't have negative numbers for number or size of dice! */ fprintf(stderr, "\r\nInvalid number and/or size of dice!\r\n"); exit(1); } /* Figure out our display mode. */ if (argv[3]) { if (!stricmp(argv[3], "b")) mode = 'b'; else if (!stricmp(argv[3], "i")) mode = 'i'; else mode = 't'; } /* We've got a display mode, so prepare for it... */ if (mode == 'i') { show_ind = 1; individual_rolls = (int *)calloc(num, sizeof(int)); if (!individual_rolls) { fprintf(stderr, "\r\nMemory allocation error 1\r\n"); exit(1); } } else if (mode == 'b') { show_tab = 1; individual_rolls = (int *)calloc(size + 1, sizeof(int)); if (!individual_rolls) { fprintf(stderr, "\r\nMemory allocation error 2\r\n"); exit(1); } } else show_tot = 1; /* ************************************************************* * * * Now roll the dice and keep track of the results according * * to the appropriate display method. * * * ************************************************************* */ printf("\r\nRolling the dice...\r\n"); do { one_die = dice(1, size); if (show_tab) individual_rolls[one_die] += 1; else if (show_ind) individual_rolls[cnt] = one_die; total += one_die; cnt += 1; } while (num > cnt); /* ****************************************************************** * * * Now to display the results using the appropriate display mode. * * * ****************************************************************** */ /* Just show the total. */ if (show_tot) sprintf(buf, "\r\nRolled %dd%d, result: %d\r\n", num, size, total); /* Show tabulated results for each pip. */ else if (show_tab) { for (cnt = 1; cnt <= size; cnt++) { if (individual_rolls[cnt] > 0) { sprintf(buf + strlen(buf), "\r\nPip %d: %d times", cnt, individual_rolls[cnt]); } } sprintf(buf + strlen(buf), "\r\n\r\nFinal Total for %dd%d: %d\r\n", num, size, total); } /* Show each individual roll. */ else if (show_ind) { line_len = 0; strcpy(buf, "\r\n"); for (cnt = 0; cnt < num; cnt++) { /* Let's try to do some lining up of the numbers, in the event they should wrap longer than one line. The easier to see them all. Highest die I've seen required is 1d1000 (for Living Steel), so I'll accomodate dice up to 4 digits in size. After that, tough noogies :p If this were perl, we could do some cool stuff with references to always have an exactly correctly %d statement, but C just doesn't allow for it! Hmm... a perl version of this program! Version 2.0, here I come :D */ if (size < 10) line_len += sprintf(buf + strlen(buf), "%d ", individual_rolls[cnt]); else if (size < 100) line_len += sprintf(buf + strlen(buf), "%2d ", individual_rolls[cnt]); else if (size < 1000) line_len += sprintf(buf + strlen(buf), "%3d ", individual_rolls[cnt]); else if (size < 10000) line_len += sprintf(buf + strlen(buf), "%4d ", individual_rolls[cnt]); else line_len += sprintf(buf + strlen(buf), "%d ", individual_rolls[cnt]); if (line_len > 69) { strcat(buf, "\r\n"); line_len = 0; } if (strlen(buf) > sizeof(buf) - 1) { /* We'll have overwritten a little bit of memory by now, so let's stop before we overwrite any more! */ fprintf(stderr, "\r\nBuffer overflow error generating output!\r\n"); exit(1); } } sprintf(buf + strlen(buf), "\r\n\r\nFinal Total for %dd%d: %d\r\n", num, size, total); if (strlen(buf) > sizeof(buf) - 1) { fprintf(stderr, "\r\nBuffer overflow error generating output!\r\n"); exit(1); } } printf(buf); if (individual_rolls) free(individual_rolls); return 0; } /* ***************************************** * * * Below is the random number generators. * * * * *************************************** */ /* random number generator consants */ #define IA 16807 #define IM 2147483647 #define AM (1.0f / IM) #define IQ 127773 #define IR 2836 #define MASK 123459876 /* current number in the random sequence */ static long idum = 42; int rand(void) { long k; long ans; idum ^= MASK; k = idum / IQ; idum = IA * (idum - k * IQ) - IR * k; if (idum < 0) idum += IM; ans = idum; idum ^= MASK; return(ans); } void hseed(long seed) { idum = seed; }