#include "chess.h"
 
#include "data.h"
 
/* last modified 02/26/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Test() is used to test the program against a suite of test positions to   *
 
 *   measure its performance on a particular machine, or to evaluate its skill *
 
 *   after modifying it in some way.                                           *
 
 *                                                                             *
 
 *   The test is initiated by using the "test <filename>" command to read in   *
 
 *   the suite of problems from file <filename>.  The format of this file is   *
 
 *   as follows:                                                               *
 
 *                                                                             *
 
 *   Setboard <forsythe-string>:  This sets the board position using the usual *
 
 *   forsythe notation (see module SetBoard() in setc for a full ex-           *
 
 *   planation of the syntax).                                                 *
 
 *                                                                             *
 
 *   Solution <move1> <move2> ... <moven>:  this provides a solution move (or  *
 
 *   set of solution moves if more than one is correct).  If the search finds  *
 
 *   one of these moves, then the prblem is counted as correct, otherwise it   *
 
 *   is counted wrong.                                                         *
 
 *                                                                             *
 
 *   After reading these two lines, the program then searches to whatever time *
 
 *   or depth limit has been set, when it reaches the end-of-file condition or *
 
 *   when it reads a record containing the string "end" it then displays the   *
 
 *   number correct and the number missed.                                     *
 
 *                                                                             *
 
 *   There are two test modules here.  Test() handles the specific Crafty test *
 
 *   data format (dates back to Cray Blitz days) while TestEPD() handles the   *
 
 *   EPD-style test positions which is more concise.  Other than the parsing   *
 
 *   differences, these are identical modules.                                 *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void Test(char *filename) {
 
  FILE *test_input;
 
  int i, move, right = 0, wrong = 0, correct;
 
  uint64_t nodes = 0;
 
  char *eof, *delim;
 
  float avg_depth = 0.0;
 
  TREE *const tree = block[0];
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Read in the position and then the solutions.  After     *
 
 *  executing a search to find the best move (according to  *
 
 *  the program, anyway) compare it against the list of     *
 
 *  solutions and count it right or wrong.                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  fopen_s (&test_input, filename, "r");
 
  if (!test_input) {
 
    printf("file %s does not exist.\n", filename
);  
    return;
 
  }
 
  Print(4095, "\n");
 
  eof 
= fgets(buffer
, 4096, test_input
); 
  else {
 
    TestEPD(filename);
 
    return;
 
  }
 
  if (book_file) {
 
    book_file = 0;
 
  }
 
  if (books_file) {
 
    books_file = 0;
 
  }
 
  while (1) {
 
    if (eof) {
 
      if (delim)
 
        *delim = 0;
 
      if (delim)
 
        *delim = ' ';
 
    } else
 
      break;
 
    nargs = ReadParse(buffer, args, " ;");
 
      break;
 
    else if (!strcmp(args
[0], "title")) {  
      Print(4095,
 
          "=============================================="
 
          "========================\n");
 
      Print(4095, "! ");
 
      len = 0;
 
      for (i = 1; i < nargs; i++) {
 
        Print(4095, "%s ", args[i]);
 
        if (len > 65)
 
          break;
 
      }
 
      for (i = len; i < 67; i++)
 
      Print(4095, "!\n");
 
      Print(4095,
 
          "=============================================="
 
          "========================\n");
 
    } else if (strcmp(args
[0], "solution")) {  
      Option(tree);
 
    } else {
 
      number_of_solutions = 0;
 
      solution_type = 0;
 
      Print(4095, "solution ");
 
      for (i = 1; i < nargs; i++) {
 
        if (args
[i
][strlen(args
[i
]) - 1] == '?') {  
          solution_type = 1;
 
          args
[i
][strlen(args
[i
]) - 1] = '\0'; 
        } else if (*(args 
+ i
)[strlen(args
[i
]) - 1] == '!') {  
          solution_type = 0;
 
          args
[i
][strlen(args
[i
]) - 1] = '\0'; 
        }
 
        move = InputMove(tree, args[i], 0, game_wtm, 0, 0);
 
        if (move) {
 
          solutions[number_of_solutions] = move;
 
          Print(4095, "%d. %s", (number_of_solutions++) + 1, OutputMove(tree,
 
                  move, 0, game_wtm));
 
          if (solution_type == 1)
 
            Print(4095, "? ");
 
          else
 
            Print(4095, "  ");
 
        } else
 
          DisplayChessBoard(stdout, tree->position);
 
      }
 
      Print(4095, "\n");
 
      InitializeHashTables();
 
      last_pv.pathd = 0;
 
      thinking = 1;
 
      tree->status[1] = tree->status[0];
 
      (void) Iterate(game_wtm, think, 0);
 
      thinking = 0;
 
      nodes += tree->nodes_searched;
 
      avg_depth += (float) iteration_depth;
 
      time += (end_time 
- start_time
);  
      correct = solution_type;
 
      for (i = 0; i < number_of_solutions; i++) {
 
        if (!solution_type) {
 
          if (solutions[i] == tree->pv[1].path[1])
 
            correct = 1;
 
        } else if (solutions[i] == tree->pv[1].path[1])
 
          correct = 0;
 
      }
 
      if (correct) {
 
        right++;
 
        Print(4095, "----------------------> solution correct (%d/%d).\n",
 
            right, right + wrong);
 
      } else {
 
        wrong++;
 
        Print(4095, "----------------------> solution incorrect (%d/%d).\n",
 
            right, right + wrong);
 
      }
 
    }
 
    eof 
= fgets(buffer
, 4096, test_input
); 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now print the results.                                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (right + wrong) {
 
    Print(4095, "\n\n\n");
 
    Print(4095, "test results summary:\n\n");
 
    Print(4095, "total positions searched..........%12d\n", right + wrong);
 
    Print(4095, "number right......................%12d\n", right);
 
    Print(4095, "number wrong......................%12d\n", wrong);
 
    Print(4095, "percentage right..................%12d\n",
 
        right * 100 / (right + wrong));
 
    Print(4095, "percentage wrong..................%12d\n",
 
        wrong * 100 / (right + wrong));
 
    Print(4095, "total nodes searched..............%12" PRIu64 "\n", nodes);
 
    Print(4095, "average search depth..............%12.1f\n",
 
        avg_depth / (right + wrong));
 
    Print(4095, "nodes per second..................%12" PRIu64 "\n",
 
        nodes 
* 100 / Max
(time, 1)); 
    Print(4095, "total time........................%12s\n",
 
  }
 
  input_stream = stdin;
 
  early_exit = 99;
 
}
 
 
 
/* last modified 02/26/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   TestEPD() is used to test the program against a suite of test positions   *
 
 *   to measure its performance on a particular machine, or to evaluate its    *
 
 *   skill after modifying it in some way.                                     *
 
 *                                                                             *
 
 *   The test is initiated by using the "test <filename>" command to read in   *
 
 *   the suite of problems from file <filename>.  The format of this file is   *
 
 *   as follows:                                                               *
 
 *                                                                             *
 
 *   <forsythe-string>  am/bm move1 move2 etc; title "xxx"                     *
 
 *                                                                             *
 
 *   Am means "avoid move" and bm means "best move".  Each test position may   *
 
 *   have multiple moves to avoid or that are best, but both am and bm may not *
 
 *   appear on one position.                                                   *
 
 *                                                                             *
 
 *   The title is just a comment that is given in the program output to make   *
 
 *   it easier to match output to specific positions.                          *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
void TestEPD(char *filename) {
 
  FILE *test_input;
 
  int i, move, right = 0, wrong = 0, correct;
 
  uint64_t nodes = 0;
 
  char *eof, *mvs, *title;
 
  float avg_depth = 0.0;
 
  TREE *const tree = block[0];
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Read in the position and then the solutions.  After     *
 
 *  executing a search to find the best move (according to  *
 
 *  the program, anyway) compare it against the list of     *
 
 *  solutions and count it right or wrong.                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  fopen_s(&test_input, filename, "r"); // Pierre-Marie Baty -- use safe version
 
  if (!test_input) {
 
    printf("file %s does not exist.\n", filename
);  
    return;
 
  }
 
  if (book_file) {
 
    book_file = 0;
 
  }
 
  if (books_file) {
 
    books_file = 0;
 
  }
 
  while (1) {
 
    eof 
= fgets(buffer
, 4096, test_input
); 
    if (eof) {
 
      char *delim;
 
 
 
      if (delim)
 
        *delim = 0;
 
      if (delim)
 
        *delim = ' ';
 
    } else
 
      break;
 
    if (!mvs)
 
    if (!mvs)
 
      Print(4095, "Warning. am/bm field missing, input string follows\n%s\n",
 
          buffer);
 
    if (mvs)
 
      mvs++;
 
    if (mvs)
 
      *(mvs - 1) = 0;
 
    if (title)
 
      *(title - 1) = 0;
 
    if (title) {
 
      title 
= strchr(title
, '\"') + 1; 
      if (title) {
 
        }
 
      }
 
      Print(4095,
 
          "=============================================="
 
          "========================\n");
 
      Print(4095, "! ");
 
      Print(4095, "%s ", title);
 
      for (i = 0; i < len; i++)
 
      Print(4095, "!\n");
 
      Print(4095,
 
          "=============================================="
 
          "========================\n");
 
    }
 
    Option(tree);
 
    if (mvs) {
 
      nargs = ReadParse(mvs, args, " ;");
 
      number_of_solutions = 0;
 
      solution_type = 0;
 
        solution_type = 1;
 
      Print(4095, "solution ");
 
      for (i = 1; i < nargs; i++) {
 
          break;
 
        move = InputMove(tree, args[i], 0, game_wtm, 0, 0);
 
        if (move) {
 
          solutions[number_of_solutions] = move;
 
          Print(4095, "%d. %s", (number_of_solutions++) + 1, OutputMove(tree,
 
                  move, 0, game_wtm));
 
          if (solution_type == 1)
 
            Print(4095, "? ");
 
          else
 
            Print(4095, "  ");
 
        } else
 
          DisplayChessBoard(stdout, tree->position);
 
      }
 
    }
 
    Print(4095, "\n");
 
    InitializeHashTables();
 
    last_pv.pathd = 0;
 
    thinking = 1;
 
    tree->status[1] = tree->status[0];
 
    (void) Iterate(game_wtm, think, 0);
 
    thinking = 0;
 
    nodes += tree->nodes_searched;
 
    avg_depth += (float) iteration_depth;
 
    time += (end_time 
- start_time
);  
    correct = solution_type;
 
    for (i = 0; i < number_of_solutions; i++) {
 
      if (!solution_type) {
 
        if (solutions[i] == tree->pv[1].path[1])
 
          correct = 1;
 
      } else if (solutions[i] == tree->pv[1].path[1])
 
        correct = 0;
 
    }
 
    if (correct) {
 
      right++;
 
      Print(4095, "----------------------> solution correct (%d/%d).\n",
 
          right, right + wrong);
 
    } else {
 
      wrong++;
 
      Print(4095, "----------------------> solution incorrect (%d/%d).\n",
 
          right, right + wrong);
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now print the results.                                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (right + wrong) {
 
    Print(4095, "\n\n\n");
 
    Print(4095, "test results summary:\n\n");
 
    Print(4095, "total positions searched..........%12d\n", right + wrong);
 
    Print(4095, "number right......................%12d\n", right);
 
    Print(4095, "number wrong......................%12d\n", wrong);
 
    Print(4095, "percentage right..................%12d\n",
 
        right * 100 / (right + wrong));
 
    Print(4095, "percentage wrong..................%12d\n",
 
        wrong * 100 / (right + wrong));
 
    Print(4095, "total nodes searched..............%12" PRIu64 "\n", nodes);
 
    Print(4095, "average search depth..............%12.1f\n",
 
        avg_depth / (right + wrong));
 
    Print(4095, "nodes per second..................%12" PRIu64 "\n",
 
        nodes 
* 100 / Max
(1, time)); 
    Print(4095, "total time........................%12s\n",
 
  }
 
  input_stream = stdin;
 
  early_exit = 99;
 
}