/* perft.c -- a small command-line "perft" (performance test / move
 * path enumeration test) tool built on the SAN Kit library.
 *
 * perft counts the number of leaf nodes in the legal-move tree to a
 * given depth from a given position -- the standard first sanity
 * check for any chess move generator, since the correct counts for
 * the initial position are well known:
 *
 *   depth 1:               20
 *   depth 2:              400
 *   depth 3:            8,902
 *   depth 4:          197,281
 *   depth 5:        4,865,609
 *   depth 6:      119,060,324
 *
 * All of the actual counting is done by the library's own
 * SANEnumerate() (see sanenu.c and examples/07_perft_enumerate.c);
 * this program is a thin, scriptable command-line wrapper around it
 * that also accepts a FEN to start from and reports timing.
 *
 * Usage:
 *   perft [-f FEN] DEPTH
 *
 * Examples:
 *   perft 5
 *   perft -f "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1" 4
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "sandef.h"
#include "sanvar.h"

#include "sanint.h"
#include "sanenu.h"
#include "sanfen.h"

static void
usage (const char *progname)
{
  fprintf (stderr, "usage: %s [-f FEN] DEPTH\n", progname);
  fprintf (stderr, "       %s [-f FEN] -d MAXDEPTH   "
                    "(run depth 1..MAXDEPTH)\n", progname);
  return;
}

int
main (int argc, char *argv[])
{
  int i;
  char *fen;
  siT depth, maxdepth, d;
  liT nodes;
  clock_t t0, t1;
  double secs;

  fen = NULL;
  depth = 0;
  maxdepth = 0;

  i = 1;
  while (i < argc)
    {
      if ((strcmp (argv[i], "-f") == 0) && (i + 1 < argc))
        {
          fen = argv[i + 1];
          i += 2;
        }
      else if ((strcmp (argv[i], "-d") == 0) && (i + 1 < argc))
        {
          maxdepth = (siT) atoi (argv[i + 1]);
          i += 2;
        }
      else
        {
          depth = (siT) atoi (argv[i]);
          i++;
        };
    };

  if ((depth <= 0) && (maxdepth <= 0))
    {
      usage (argv[0]);
      return (1);
    };

  SANInit ();

  if (fen != NULL)
    {
      if (!SANFENSet (fen))
        {
          fprintf (stderr, "%s: not a valid FEN: %s\n", argv[0], fen);
          return (1);
        };
      printf ("Position: %s\n", fen);
    }
  else
    printf ("Position: initial\n");

  if (maxdepth > 0)
    {
      for (d = 1; d <= maxdepth; d++)
        {
          printf ("--- depth %d ---\n", d);
          t0 = clock ();
          nodes = SANEnumerate (d);
          t1 = clock ();
          secs = ((double) (t1 - t0)) / CLOCKS_PER_SEC;
          printf ("perft(%d) = %ld", d, nodes);
          if (secs > 0.0)
            printf ("   (%.2fs, %.0f nodes/sec)", secs, nodes / secs);
          printf ("\n\n");
        };
    }
  else
    {
      t0 = clock ();
      nodes = SANEnumerate (depth);
      t1 = clock ();
      secs = ((double) (t1 - t0)) / CLOCKS_PER_SEC;
      printf ("\nperft(%d) = %ld", depth, nodes);
      if (secs > 0.0)
        printf ("   (%.2fs, %.0f nodes/sec)", secs, nodes / secs);
      printf ("\n");
    };

  return (0);
}
