Add forgotten files 1.4.70b
[polyglot.git] / epd.c
diff --git a/epd.c b/epd.c
index af427ad..18f0248 100644 (file)
--- a/epd.c
+++ b/epd.c
-\r
-// epd.c\r
-\r
-// includes\r
-\r
-#include <errno.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "board.h"\r
-#include "engine.h"\r
-#include "epd.h"\r
-#include "fen.h"\r
-#include "line.h"\r
-#include "main.h"\r
-#include "move.h"\r
-#include "move_legal.h"\r
-#include "option.h"\r
-#include "parse.h"\r
-#include "san.h"\r
-#include "uci.h"\r
-#include "util.h"\r
-\r
-\r
-// macros\r
-\r
-#define  StringSize 4096\r
-\r
-// constants\r
-\r
-static const bool UseDebug = FALSE;\r
-static const bool UseTrace = FALSE;\r
-\r
-// variables\r
-\r
-static int MinDepth;\r
-static int MaxDepth;\r
-\r
-static double MaxTime;\r
-static double MinTime;\r
-\r
-static int DepthDelta;\r
-\r
-static int FirstMove;\r
-static int FirstDepth;\r
-static int FirstSelDepth;\r
-static int FirstScore;\r
-static double FirstTime;\r
-static uint64 FirstNodeNb;\r
-static move_t FirstPV[LineSize];\r
-\r
-static int LastMove;\r
-static int LastDepth;\r
-static int LastSelDepth;\r
-static int LastScore;\r
-static double LastTime;\r
-static uint64 LastNodeNb;\r
-static move_t LastPV[LineSize];\r
-\r
-static my_timer_t Timer[1];\r
-\r
-// prototypes\r
-\r
-static void epd_test_file  (const char file_name[]);\r
-\r
-static bool is_solution    (int move, const board_t * board, const char bm[], const char am[]);\r
-static bool string_contain (const char string[], const char substring[]);\r
-\r
-static bool engine_step    ();\r
-\r
-// functions\r
-\r
-// epd_test()\r
-\r
-void epd_test(int argc, char * argv[]) {\r
-\r
-   int i;\r
-   const char * epd_file;\r
-\r
-   epd_file = NULL;\r
-   my_string_set(&epd_file,"wac.epd");\r
-\r
-   MinDepth = 8;\r
-   MaxDepth = 63;\r
-\r
-   MinTime = 1.0;\r
-   MaxTime = 5.0;\r
-\r
-   DepthDelta = 3;\r
-\r
-   for (i = 1; i < argc; i++) {\r
-\r
-      if (FALSE) {\r
-\r
-      } else if (my_string_equal(argv[i],"epd-test")) {\r
-\r
-         // skip\r
-\r
-      } else if (my_string_equal(argv[i],"-epd")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         my_string_set(&epd_file,argv[i]);\r
-\r
-      } else if (my_string_equal(argv[i],"-min-depth")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         MinDepth = atoi(argv[i]);\r
-\r
-      } else if (my_string_equal(argv[i],"-max-depth")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         MaxDepth = atoi(argv[i]);\r
-\r
-      } else if (my_string_equal(argv[i],"-min-time")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         MinTime = atof(argv[i]);\r
-\r
-      } else if (my_string_equal(argv[i],"-max-time")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         MaxTime = atof(argv[i]);\r
-\r
-      } else if (my_string_equal(argv[i],"-depth-delta")) {\r
-\r
-         i++;\r
-         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");\r
-\r
-         DepthDelta = atoi(argv[i]);\r
-\r
-      } else {\r
-\r
-         my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]);\r
-      }\r
-   }\r
-\r
-   if(MinTime>MaxTime){\r
-       MaxTime=MinTime;\r
-   }\r
-  \r
-   epd_test_file(epd_file);\r
-}\r
-\r
-// epd_test_file()\r
-\r
-static void epd_test_file(const char file_name[]) {\r
-\r
-   FILE * file;\r
-   int hit, tot;\r
-   char epd[StringSize];\r
-   char am[StringSize], bm[StringSize], id[StringSize];\r
-   board_t board[1];\r
-   char string[StringSize];\r
-   int move;\r
-   char pv_string[StringSize];\r
-   bool correct;\r
-   double depth_tot, time_tot, node_tot;\r
-   int line=0;\r
-\r
-   ASSERT(file_name!=NULL);\r
-\r
-   // init\r
-\r
-   file = fopen(file_name,"r");\r
-   if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
-\r
-   hit = 0;\r
-   tot = 0;\r
-\r
-   depth_tot = 0.0;\r
-   time_tot = 0.0;\r
-   node_tot = 0.0;\r
-\r
-   printf("\nEngineName=%s\n",option_get_string(Option,"EngineName"));\r
-\r
-   printf("\n[Search parameters: MaxDepth=%d   MaxTime=%.1f   DepthDelta=%d   MinDepth=%d   MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime);\r
-\r
-   // loop\r
-\r
-   while (my_file_read_line(file,epd,StringSize)) {\r
-       line++;\r
-       if(my_string_whitespace(epd)) continue;\r
-      if (UseTrace) printf("%s\n",epd);\r
-\r
-      if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,"");\r
-      if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,"");\r
-      if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,"");\r
-\r
-      if (my_string_empty(am) && my_string_empty(bm)) {\r
-          my_fatal("epd_test(): no am or bm field at line %d\n",line);\r
-      }\r
-\r
-      // init\r
-\r
-      uci_send_ucinewgame(Uci);\r
-      uci_send_isready_sync(Uci);\r
-\r
-      ASSERT(!Uci->searching);\r
-\r
-      // position\r
-      if (!board_from_fen(board,epd)) ASSERT(FALSE);\r
-      if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE);\r
-\r
-      engine_send(Engine,"position fen %s");\r
-\r
-      // search\r
-\r
-      my_timer_start(Timer); // also resets\r
-      \r
-      // which ones of the next two alternatives is best?\r
-      engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth);\r
-      //engine_send(Engine,"go infinite");\r
-\r
-      // engine data\r
-\r
-      board_copy(Uci->board,board);\r
-\r
-      uci_clear(Uci);\r
-      Uci->searching = TRUE;\r
-      Uci->pending_nb++;\r
-\r
-      FirstMove = MoveNone;\r
-      FirstDepth = 0;\r
-      FirstSelDepth = 0;\r
-      FirstScore = 0;\r
-      FirstTime = 0.0;\r
-      FirstNodeNb = 0;\r
-      line_clear(FirstPV);\r
-\r
-      LastMove = MoveNone;\r
-      LastDepth = 0;\r
-      LastSelDepth = 0;\r
-      LastScore = 0;\r
-      LastTime = 0.0;\r
-      LastNodeNb = 0;\r
-      line_clear(LastPV);\r
-\r
-      // parse engine output\r
-\r
-      while (!engine_eof(Engine) && engine_step()) {\r
-          bool stop=FALSE;\r
-\r
-         // stop search?\r
-//          printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer));\r
-          if (Uci->depth > MaxDepth){\r
-              my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth);\r
-              stop=TRUE;\r
-          }else if(my_timer_elapsed_real(Timer) >= MaxTime){\r
-              my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime);\r
-              stop=TRUE;\r
-          }else if(Uci->depth - FirstDepth >= DepthDelta){\r
-              if(Uci->depth > MinDepth){\r
-                  if(Uci->time >= MinTime){\r
-                      if(is_solution(FirstMove,board,bm,am)){\r
-                          my_log("POLYGLOT Solution found\n",MaxTime);\r
-                          stop=TRUE;\r
-                      }\r
-                  }\r
-              }\r
-          }\r
-          if(stop){\r
-              my_log("POLYGLOT Stopping engine\n");\r
-              engine_send(Engine,"stop");\r
-              break;\r
-          }\r
-      }\r
-      \r
-      move = FirstMove;\r
-      correct = is_solution(move,board,bm,am);\r
-\r
-      if (correct) hit++;\r
-      tot++;\r
-\r
-      if (correct) {\r
-          depth_tot += ((double)FirstDepth);\r
-         time_tot += FirstTime;\r
-         node_tot += ((double)((sint64)FirstNodeNb));\r
-      }\r
-\r
-      printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit);\r
-\r
-      if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE);\r
-      printf(" score=%+6.2f    pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",((double)LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string);\r
-   }\r
-\r
-   printf("\nscore=%d/%d",hit,tot);\r
-\r
-   if (hit != 0) {\r
-\r
-       depth_tot /= ((double)hit);\r
-       time_tot /= ((double)hit);\r
-       node_tot /= ((double)hit);\r
-\r
-      printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot);\r
-   }\r
-\r
-   printf("\n");\r
-\r
-   fclose(file);\r
-   quit();\r
-}\r
-\r
-// is_solution()\r
-\r
-static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) {\r
-\r
-   char move_string[256];\r
-   bool correct;\r
-\r
-   ASSERT(move!=MoveNone);\r
-   ASSERT(bm!=NULL);\r
-   ASSERT(am!=NULL);\r
-\r
-   if (!move_is_legal(move,board)) {\r
-      board_disp(board);\r
-      move_disp(move,board);\r
-      printf("\n\n");\r
-   }\r
-\r
-   ASSERT(move_is_legal(move,board));\r
-\r
-   if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);\r
-\r
-   correct = FALSE;\r
-   if (!my_string_empty(bm)) {\r
-      correct = string_contain(bm,move_string);\r
-   } else if (!my_string_empty(am)) {\r
-      correct = !string_contain(am,move_string);\r
-   } else {\r
-      ASSERT(FALSE);\r
-   }\r
-\r
-   return correct;\r
-}\r
-\r
-// epd_get_op()\r
-\r
-bool epd_get_op(const char record[], const char opcode[], char string[], int size) {\r
-\r
-   char op[256];\r
-   int len;\r
-   const char *p_start, *p_end;\r
-\r
-   ASSERT(record!=NULL);\r
-   ASSERT(opcode!=NULL);\r
-   ASSERT(string!=NULL);\r
-   ASSERT(size>0);\r
-\r
-   // find the opcode\r
-\r
-   sprintf(op," %s ",opcode); \r
-\r
-   p_start = strstr(record,op);\r
-   if (p_start == NULL){\r
-          sprintf(op,";%s ",opcode); \r
-          p_start = strstr(record,op);\r
-          if (p_start == NULL){\r
-              return FALSE;\r
-          }\r
-   }\r
-\r
-   // skip the opcode\r
-\r
-   p_start += strlen(op);\r
-\r
-   // find the end\r
-   p_end = strchr(p_start,';');\r
-   if (p_end == NULL) return FALSE;\r
-\r
-   // calculate the length\r
-\r
-   len = p_end - p_start;\r
-   if (size < len+1) my_fatal("epd_get_op(): size < len+1\n");\r
-\r
-   strncpy(string,p_start,len);\r
-   string[len] = '\0';\r
-\r
-   return TRUE;\r
-}\r
-\r
-// string_contain()\r
-\r
-static bool string_contain(const char string[], const char substring[]) {\r
-\r
-   char new_string[StringSize], *p;\r
-\r
-   strcpy(new_string,string); // HACK\r
-\r
-   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {\r
-      if (my_string_equal(p,substring)) return TRUE;\r
-   }\r
-\r
-   return FALSE;\r
-}\r
-\r
-// engine_step()\r
-\r
-static bool engine_step() {\r
-\r
-   char string[StringSize];\r
-   int event;\r
-\r
-   engine_get(Engine,string);\r
-   event = uci_parse(Uci,string);\r
-\r
-   if ((event & EVENT_MOVE) != 0) {\r
-\r
-      return FALSE;\r
-   }\r
-\r
-   if ((event & EVENT_PV) != 0) {\r
-\r
-      LastMove = Uci->best_pv[0];\r
-      LastDepth = Uci->best_depth;\r
-      LastSelDepth = Uci->best_sel_depth;\r
-      LastScore = Uci->best_score;\r
-      LastTime = Uci->time;\r
-      LastNodeNb = Uci->node_nb;\r
-      line_copy(LastPV,Uci->best_pv);\r
-\r
-      if (LastMove != FirstMove) {\r
-         FirstMove = LastMove;\r
-         FirstDepth = LastDepth;\r
-         FirstSelDepth = LastSelDepth;\r
-         FirstScore = LastScore;\r
-         FirstTime = LastTime;\r
-         FirstNodeNb = LastNodeNb;\r
-         line_copy(FirstPV,LastPV);\r
-      }\r
-   }\r
-\r
-   return TRUE;\r
-}\r
-\r
-// end of epd.cpp\r
-\r
+
+// epd.c
+
+// includes
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "board.h"
+#include "engine.h"
+#include "epd.h"
+#include "fen.h"
+#include "line.h"
+#include "main.h"
+#include "move.h"
+#include "move_legal.h"
+#include "option.h"
+#include "parse.h"
+#include "san.h"
+#include "uci.h"
+#include "util.h"
+
+
+// macros
+
+#define  StringSize 4096
+
+// constants
+
+static const bool UseDebug = FALSE;
+static const bool UseTrace = FALSE;
+
+// variables
+
+static int MinDepth;
+static int MaxDepth;
+
+static double MaxTime;
+static double MinTime;
+
+static int DepthDelta;
+
+static int FirstMove;
+static int FirstDepth;
+static int FirstSelDepth;
+static int FirstScore;
+static double FirstTime;
+static uint64 FirstNodeNb;
+static move_t FirstPV[LineSize];
+
+static int LastMove;
+static int LastDepth;
+static int LastSelDepth;
+static int LastScore;
+static double LastTime;
+static uint64 LastNodeNb;
+static move_t LastPV[LineSize];
+
+static my_timer_t Timer[1];
+
+// prototypes
+
+static void epd_test_file  (const char file_name[]);
+
+static bool is_solution    (int move, const board_t * board, const char bm[], const char am[]);
+static bool string_contain (const char string[], const char substring[]);
+
+static bool engine_step    ();
+
+// functions
+
+// epd_test()
+
+void epd_test(int argc, char * argv[]) {
+
+   int i;
+   const char * epd_file;
+
+   epd_file = NULL;
+   my_string_set(&epd_file,"wac.epd");
+
+   MinDepth = 8;
+   MaxDepth = 63;
+
+   MinTime = 1.0;
+   MaxTime = 5.0;
+
+   DepthDelta = 3;
+
+   for (i = 1; i < argc; i++) {
+
+      if (FALSE) {
+
+      } else if (my_string_equal(argv[i],"epd-test")) {
+
+         // skip
+
+      } else if (my_string_equal(argv[i],"-epd")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         my_string_set(&epd_file,argv[i]);
+
+      } else if (my_string_equal(argv[i],"-min-depth")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         MinDepth = atoi(argv[i]);
+
+      } else if (my_string_equal(argv[i],"-max-depth")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         MaxDepth = atoi(argv[i]);
+
+      } else if (my_string_equal(argv[i],"-min-time")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         MinTime = atof(argv[i]);
+
+      } else if (my_string_equal(argv[i],"-max-time")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         MaxTime = atof(argv[i]);
+
+      } else if (my_string_equal(argv[i],"-depth-delta")) {
+
+         i++;
+         if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n");
+
+         DepthDelta = atoi(argv[i]);
+
+      } else {
+
+         my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]);
+      }
+   }
+
+   if(MinTime>MaxTime){
+       MaxTime=MinTime;
+   }
+  
+   epd_test_file(epd_file);
+}
+
+// epd_test_file()
+
+static void epd_test_file(const char file_name[]) {
+
+   FILE * file;
+   int hit, tot;
+   char epd[StringSize];
+   char am[StringSize], bm[StringSize], id[StringSize];
+   board_t board[1];
+   char string[StringSize];
+   int move;
+   char pv_string[StringSize];
+   bool correct;
+   double depth_tot, time_tot, node_tot;
+   int line=0;
+
+   ASSERT(file_name!=NULL);
+
+   // init
+
+   file = fopen(file_name,"r");
+   if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno));
+
+   hit = 0;
+   tot = 0;
+
+   depth_tot = 0.0;
+   time_tot = 0.0;
+   node_tot = 0.0;
+
+   printf("\nEngineName=%s\n",option_get_string(Option,"EngineName"));
+
+   printf("\n[Search parameters: MaxDepth=%d   MaxTime=%.1f   DepthDelta=%d   MinDepth=%d   MinTime=%.1f]\n\n",MaxDepth,MaxTime,DepthDelta,MinDepth,MinTime);
+
+   // loop
+
+   while (my_file_read_line(file,epd,StringSize)) {
+       line++;
+       if(my_string_whitespace(epd)) continue;
+      if (UseTrace) printf("%s\n",epd);
+
+      if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,"");
+      if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,"");
+      if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,"");
+
+      if (my_string_empty(am) && my_string_empty(bm)) {
+          my_fatal("epd_test(): no am or bm field at line %d\n",line);
+      }
+
+      // init
+
+      uci_send_ucinewgame(Uci);
+      uci_send_isready_sync(Uci);
+
+      ASSERT(!Uci->searching);
+
+      // position
+      if (!board_from_fen(board,epd)) ASSERT(FALSE);
+      if (!board_to_fen(board,string,StringSize)) ASSERT(FALSE);
+
+      engine_send(Engine,"position fen %s",string);
+
+      // search
+
+      my_timer_start(Timer); // also resets
+      
+      // which ones of the next two alternatives is best?
+      engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth);
+      //engine_send(Engine,"go infinite");
+
+      // engine data
+
+      board_copy(Uci->board,board);
+
+      uci_clear(Uci);
+      Uci->searching = TRUE;
+      Uci->pending_nb++;
+
+      FirstMove = MoveNone;
+      FirstDepth = 0;
+      FirstSelDepth = 0;
+      FirstScore = 0;
+      FirstTime = 0.0;
+      FirstNodeNb = 0;
+      line_clear(FirstPV);
+
+      LastMove = MoveNone;
+      LastDepth = 0;
+      LastSelDepth = 0;
+      LastScore = 0;
+      LastTime = 0.0;
+      LastNodeNb = 0;
+      line_clear(LastPV);
+
+      // parse engine output
+
+      while (!engine_eof(Engine) && engine_step()) {
+          bool stop=FALSE;
+
+         // stop search?
+//          printf("Uci->time=%.2f time=%.2f\n",Uci->time,my_timer_elapsed_real(Timer));
+          if (Uci->depth > MaxDepth){
+              my_log("POLYGLOT Maximum depth %d reached\n",MaxDepth);
+              stop=TRUE;
+          }else if(my_timer_elapsed_real(Timer) >= MaxTime){
+              my_log("POLYGLOT Maximum search time %.2fs reached\n",MaxTime);
+              stop=TRUE;
+          }else if(Uci->depth - FirstDepth >= DepthDelta){
+              if(Uci->depth > MinDepth){
+                  if(Uci->time >= MinTime){
+                      if(is_solution(FirstMove,board,bm,am)){
+                          my_log("POLYGLOT Solution found\n",MaxTime);
+                          stop=TRUE;
+                      }
+                  }
+              }
+          }
+          if(stop){
+              my_log("POLYGLOT Stopping engine\n");
+              engine_send(Engine,"stop");
+              break;
+          }
+      }
+      
+      move = FirstMove;
+      correct = is_solution(move,board,bm,am);
+
+      if (correct) hit++;
+      tot++;
+
+      if (correct) {
+          depth_tot += ((double)FirstDepth);
+         time_tot += FirstTime;
+         node_tot += ((double)((sint64)FirstNodeNb));
+      }
+
+      printf("%2d: %-15s %s %4d",tot,id,correct?"OK":"--",hit);
+
+      if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(FALSE);
+      printf(" score=%+6.2f    pv [D=%2d, T=%7.2fs, N=%6dk] =%s\n",((double)LastScore)/100.0,FirstDepth,FirstTime,(int)FirstNodeNb/1000,pv_string);
+   }
+
+   printf("\nscore=%d/%d",hit,tot);
+
+   if (hit != 0) {
+
+       depth_tot /= ((double)hit);
+       time_tot /= ((double)hit);
+       node_tot /= ((double)hit);
+
+      printf(" [averages on correct positions: depth=%.1f time=%.2f nodes=%.0f]",depth_tot,time_tot,node_tot);
+   }
+
+   printf("\n");
+
+   fclose(file);
+   quit();
+}
+
+// is_solution()
+
+static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) {
+
+   char move_string[256];
+   bool correct;
+
+   ASSERT(move!=MoveNone);
+   ASSERT(bm!=NULL);
+   ASSERT(am!=NULL);
+
+   if (!move_is_legal(move,board)) {
+      board_disp(board);
+      move_disp(move,board);
+      printf("\n\n");
+   }
+
+   ASSERT(move_is_legal(move,board));
+
+   if (!move_to_san(move,board,move_string,256)) ASSERT(FALSE);
+
+   correct = FALSE;
+   if (!my_string_empty(bm)) {
+      correct = string_contain(bm,move_string);
+   } else if (!my_string_empty(am)) {
+      correct = !string_contain(am,move_string);
+   } else {
+      ASSERT(FALSE);
+   }
+
+   return correct;
+}
+
+// epd_get_op()
+
+bool epd_get_op(const char record[], const char opcode[], char string[], int size) {
+
+   char op[256];
+   int len;
+   const char *p_start, *p_end;
+
+   ASSERT(record!=NULL);
+   ASSERT(opcode!=NULL);
+   ASSERT(string!=NULL);
+   ASSERT(size>0);
+
+   // find the opcode
+
+   sprintf(op," %s ",opcode); 
+
+   p_start = strstr(record,op);
+   if (p_start == NULL){
+          sprintf(op,";%s ",opcode); 
+          p_start = strstr(record,op);
+          if (p_start == NULL){
+              return FALSE;
+          }
+   }
+
+   // skip the opcode
+
+   p_start += strlen(op);
+
+   // find the end
+   p_end = strchr(p_start,';');
+   if (p_end == NULL) return FALSE;
+
+   // calculate the length
+
+   len = p_end - p_start;
+   if (size < len+1) my_fatal("epd_get_op(): size < len+1\n");
+
+   strncpy(string,p_start,len);
+   string[len] = '\0';
+
+   return TRUE;
+}
+
+// string_contain()
+
+static bool string_contain(const char string[], const char substring[]) {
+
+   char new_string[StringSize], *p;
+
+   strcpy(new_string,string); // HACK
+
+   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {
+      if (my_string_equal(p,substring)) return TRUE;
+   }
+
+   return FALSE;
+}
+
+// engine_step()
+
+static bool engine_step() {
+
+   char string[StringSize];
+   int event;
+
+   engine_get(Engine,string);
+   event = uci_parse(Uci,string);
+
+   if ((event & EVENT_MOVE) != 0) {
+
+      return FALSE;
+   }
+
+   if ((event & EVENT_PV) != 0) {
+
+      LastMove = Uci->best_pv[0];
+      LastDepth = Uci->best_depth;
+      LastSelDepth = Uci->best_sel_depth;
+      LastScore = Uci->best_score;
+      LastTime = Uci->time;
+      LastNodeNb = Uci->node_nb;
+      line_copy(LastPV,Uci->best_pv);
+
+      if (LastMove != FirstMove) {
+         FirstMove = LastMove;
+         FirstDepth = LastDepth;
+         FirstSelDepth = LastSelDepth;
+         FirstScore = LastScore;
+         FirstTime = LastTime;
+         FirstNodeNb = LastNodeNb;
+         line_copy(FirstPV,LastPV);
+      }
+   }
+
+   return TRUE;
+}
+
+// end of epd.cpp
+