From 7a0b1464cb2858415e0d6902ccba5ade39c2c890 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Thu, 13 Apr 1995 20:22:01 +0000 Subject: [PATCH] Improved signal-catching. --- deal.c | 210 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 131 insertions(+), 79 deletions(-) diff --git a/deal.c b/deal.c index 0b1661b..bb4a2d7 100644 --- a/deal.c +++ b/deal.c @@ -1,14 +1,15 @@ /* - * cardprobs -- compute combination probabilities for Magic: The Gathering + * cardprobs -- compute combination probabilities for card draws * - * by Jeremy C. York ; cleanup, comments, and - * interface improvements by Eric Raymond . + * by Jeremy C. York ; cleanup, comments, + * generalization, and interface improvements by Eric Raymond + * . * - * If I have M special cards (for example, land cards) in my deck, and N - * total cards in my deck, and I draw k cards from that deck (*without - * replacement* -- the fact that you don't put them back into the deck - * can be important for some values of M and N), and if X counts the - * number of special cards contained in those k drawn cards... + * If I have M special cards in my deck, and N total cards in my deck, + * and I draw k cards from that deck (*without replacement* -- the + * fact that you don't put them back into the deck can be important + * for some values of M and N), and if X counts the number of special + * cards contained in those k drawn cards... * * Then X has a hypergeometric distribution, with the following formula * for probabilities: @@ -27,101 +28,142 @@ * cc cardprobs.c -lm -o cardprobs * * In the table output, a dot designates a probability less than .5% that - * rounds to zero. - */ + * rounds to zero. */ #include #include #include -#define BASEHAND 7 /* # cards in initial deal */ +#define BASE_DEFAULT 7 /* # cards in initial deal */ #define TURNS_DEFAULT 20 /* show this many turns if total is greater */ static int sx, sk, sM, sN; +static int sa, sb; -void catcher(int sig) +static void hypercatch(int sig) { putchar('\n'); if (sig == SIGFPE) (void) printf("Died while computing H(%d, %d, %d, %d)\n", sx,sk,sM,sN); else - (void) printf("Caught signal %d\n", sig); + (void) printf("Caught signal %d during hyper computation\n", sig); +} + +static void choosecatch(int sig) +{ + putchar('\n'); + if (sig == SIGFPE) + (void) printf("Died while computing choose(%d, %d)\n", sa, sb); + else + (void) printf("Caught signal %d during choose computation\n", sig); +} + +static void usage(void) +{ + (void) printf("usage: draw [-h] [-b initial] [-t turns] [-c columns] specials total\n"); + exit(0); } main(argc, argv) - int argc; - char **argv; +int argc; +char **argv; { - int turns, special, total, columns, i, j; + extern char *optarg; /* set by getopt */ + extern int optind; /* set by getopt */ double hyper_prob(); - if (argc < 3) { - (void) printf("usage: cardprobs M N [t] [c]\n"); - (void) printf(" M = # special cards\n"); - (void) printf(" N = # total cards\n"); - (void) printf(" t = # of turns (optional)\n"); - (void) printf(" c = columns in the report (optional)\n"); - } else { - special = atoi(argv[1]); - - total = atoi(argv[2]); - if (total < special) { - (void) printf("Can't have more specials than total cards!\n"); - exit(-1); - } else if (total <= BASEHAND) { - (void) printf("All specials would be in the initial hand!\n"); - exit(-1); + int status, special, total, columns, i, j; + int base = BASE_DEFAULT; + int turns = TURNS_DEFAULT; + int headers = 1; + + while ((status = getopt(argc, argv, "b:c:ht:")) != EOF) + { + switch (status) + { + case 'b': + base = atoi(optarg); + break; + + case 'c': + columns = atoi(optarg); + break; + + case 'h': + headers = 0; + break; + + case 't': + turns = atoi(optarg); + break; + + default: + usage(); } + } + + if (optind + 2 > argc) + usage(); + + special = atoi(argv[optind]); + total = atoi(argv[optind + 1]); + + if (total < special) { + (void) printf("Can't have more specials than total cards!\n"); + exit(-1); + } else if (total <= base) { + (void) printf("All specials would be in the initial hand!\n"); + exit(-1); + } - if (total - BASEHAND < TURNS_DEFAULT) - turns = total - BASEHAND; - else - turns = TURNS_DEFAULT; + if (total - base < TURNS_DEFAULT) + turns = total - base; - if (argc >= 4) - turns = atoi(argv[3]); - if (turns > total - BASEHAND) { - (void) printf("The deck can't last that long!\n"); - exit(-1); - } + if (turns > total - base) { + (void) printf("The deck can't last that long!\n"); + exit(-1); + } + columns = special + 1; + if (argc >= 5) + columns = atoi(argv[4]); + if (columns > special + 1) { + (void) printf("using %d columns because can only have ",special+1); + (void) printf("0 to %d specials\n",special); columns = special + 1; - if (argc >= 5) - columns = atoi(argv[4]); - if (columns > special + 1) { - (void) printf("using %d columns because can only have ",special+1); - (void) printf("0 to %d specials\n",special); - columns = special + 1; - } - - (void) printf("%d specials out of %d total; %d turns, %d columns\n", - special, total, turns, columns); - - (void) signal(SIGFPE, catcher); - - (void) printf(" | %% chance of this number of specials\n"); - (void) printf("Turn | "); - for (j = 0; j < columns; j++) - (void) printf("%2d ",j); - (void) printf("\n"); - (void) printf("-----+"); - for (j = 0; j < columns; j++) - (void) printf("---",j); - (void) printf("\n"); - - for (i = 1; i <= turns; i++) { - (void) printf("%2d | ",i); - for (j = 0; j < columns && j <= i + BASEHAND && j <= special; j++) - { - int p = (int)rint(hyper_prob(j, i + BASEHAND, special, total) * 100); - - if (p == 0) - (void) fputs(" . ", stdout); - else - (void) printf("%2d ", p); - } - - (void) printf("\n"); - } + } + + (void) signal(SIGFPE, hypercatch); + + if (headers) + { + (void) printf("%d in initial hand, %d specials out of %d total\n", + base, special, total); + + (void) printf(" | %% chance of given number of specials (. means < 0.5%%)\n"); + (void) printf("Turn | "); + for (j = 0; j < columns; j++) + (void) printf("%2d ",j); + (void) printf("\n"); + (void) printf("-----+"); + for (j = 0; j < columns; j++) + (void) printf("---",j); + (void) printf("\n"); + } + + for (i = 1; i <= turns; i++) { + if (headers) + (void) printf("%2d | ",i); + for (j = 0; j < columns && j <= i + base && j <= special; j++) + { + int p = (int)rint(hyper_prob(j, i + base, special, total) * 100); + + if (p == 0) + (void) fputs(" . ", stdout); + else + (void) printf("%2d ", p); + } + + (void) printf("\n"); } } @@ -151,6 +193,16 @@ double log_a_choose_b(a,b) { double lgamma(); + sa = a; + sb = b; + + signal(SIGFPE, choosecatch); + return(lgamma((double) (a+1)) - lgamma((double) (b+1)) - lgamma((double) (a-b+1))); + + signal(SIGFPE, hypercatch); + } + +/* cardprobs.c ends here */ -- 2.43.0