]> thyrsus.com Git - deal.git/commitdiff
Improved signal-catching.
authorEric S. Raymond <esr@thyrsus.com>
Thu, 13 Apr 1995 20:22:01 +0000 (20:22 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 13 Apr 1995 20:22:01 +0000 (20:22 +0000)
deal.c

diff --git a/deal.c b/deal.c
index 0b1661b9c3ae20de47827065c2d382f0d60ca37e..bb4a2d701a1983e8a19454e0bc14653a67fb22db 100644 (file)
--- 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 <jeremy@stat.cmu.edu>; cleanup, comments, and
- * interface improvements by Eric Raymond <esr@snark.thyrsus.com>.
+ * by Jeremy C. York <jeremy@stat.cmu.edu>; cleanup, comments, 
+ * generalization, and interface improvements by Eric Raymond
+ * <esr@snark.thyrsus.com>.
  *
- * 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:
  *     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 <stdio.h>
 #include <math.h>
 #include <signal.h>
 
-#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 */