chiark / gitweb /
mm: Add built-in option for running an internal tournament.
[mm] / mm.c
diff --git a/mm.c b/mm.c
index 3048108456f7156184a6907b507c9ab5175ff2d5..7ed9b16ff0ca1bddd5ea28370d259f99b714f1a3 100644 (file)
--- a/mm.c
+++ b/mm.c
@@ -28,6 +28,7 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#include <assert.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -35,6 +36,7 @@
 #include <time.h>
 
 #include <mLib/alloc.h>
+#include <mLib/darray.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
@@ -511,6 +513,99 @@ again:
 static void sp_update(void *ss, const dig *g, unsigned b, unsigned w)
   { spc *s = ss; cp_update(s->c, g, b, w); }
 
+/*----- Full tournament stuff ---------------------------------------------*/
+
+DA_DECL(uint_v, unsigned);
+
+typedef struct allstats {
+  const mm *m;
+  unsigned f;
+#define AF_VERBOSE 1u
+  uint_v gmap;
+  unsigned long g;
+  unsigned long n;
+  clock_t t;
+} allstats;
+
+static void dorunone(allstats *a, dig *s)
+{
+  ratectx *r = rate_new(a->m, s);
+  clock_t t = 0, t0, t1;
+  cpc *c;
+  int n = 0;
+  const dig *g;
+  unsigned b, w;
+
+  if (a->f & AF_VERBOSE) {
+    print_guess(a->m, s);
+    fputs(": ", stdout);
+    fflush(stdout);
+  }
+    
+  c = cpc_new(a->m, CPCF_QUIET);
+  for (;;) {
+    t0 = clock();
+    g = cp_guess(c);
+    t1 = clock();
+    t += t1 - t0;
+    assert(g);
+    n++;
+    rate(r, g, &b, &w);
+    if (b == a->m->k)
+      break;
+    t0 = clock();
+    cp_update(c, g, b, w);
+    t1 = clock();
+    t += t1 - t0;    
+  }
+  a->t += t;
+  a->g += n;
+  while (DA_LEN(&a->gmap) <= n)
+    DA_PUSH(&a->gmap, 0);
+  DA(&a->gmap)[n]++;
+  rate_free(r);
+  cpc_free(c);
+
+  if (a->f & AF_VERBOSE)
+    printf("%2u (%5.2fs)\n", n, (double)t/CLOCKS_PER_SEC);
+}
+
+static void dorunall(allstats *a, dig *s, unsigned i)
+{
+  dig j;
+
+  if (i >= a->m->k) {
+    dorunone(a, s);
+    a->n++;
+  } else {
+    for (j = 0; j < a->m->n; j++) {
+      s[i] = j;
+      dorunall(a, s, i + 1);
+    }
+  }
+}
+
+static void run_all(const mm *m)
+{
+  dig *s = xmalloc(m->k * sizeof(dig));
+  allstats a;
+  unsigned i;
+
+  a.m = m;
+  a.f = AF_VERBOSE;
+  DA_CREATE(&a.gmap);
+  a.n = 0;
+  a.g = 0;
+  a.t = 0;
+  dorunall(&a, s, 0);
+  xfree(s);
+
+  for (i = 1; i < DA_LEN(&a.gmap); i++)
+    printf("%2u guesses: %5u games\n", i, DA(&a.gmap)[i]);
+  printf("Average: %.4f (%.2fs)\n",
+        (double)a.g/a.n, (double)a.t/(a.n * CLOCKS_PER_SEC));
+}
+
 /*----- Main game logic ---------------------------------------------------*/
 
 static int play(const mm *m,
@@ -553,15 +648,17 @@ int main(int argc, char *argv[])
       { "computer",    0,      0,      'C' },
       { "human",       0,      0,      'H' },
       { "solver",      0,      0,      'S' },
+      { "all",         0,      0,      'a' },
       { 0,             0,      0,      0 }
     };
-    int i = mdwopt(argc, argv, "CHS", opt, 0, 0, 0);
+    int i = mdwopt(argc, argv, "CHSa", opt, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
       case 'C': h = 0; break;
       case 'H': h = 1; break;
       case 'S': h = 2; break;
+      case 'a': h = 99; break;
       default:
        exit(1);
     }
@@ -616,6 +713,10 @@ int main(int argc, char *argv[])
       n = play(&m, hp_rate, &m, sp_guess, sp_update, ss);
       spc_free(ss);
     } break;
+    case 99:
+      run_all(&m);
+      return (0);
+      break;
     default:
       abort();
   }