home *** CD-ROM | disk | FTP | other *** search
/ Dream 57 / Amiga_Dream_57.iso / Amiga / Jeux / Reflexion / Crafty-15.19.lha / crafty-15.19 / src / learn.c < prev    next >
C/C++ Source or Header  |  1998-09-13  |  48KB  |  1,176 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <time.h>
  5. #include <string.h>
  6. #include "chess.h"
  7. #include "data.h"
  8. #if defined(UNIX)
  9. #  include <unistd.h>
  10. #endif
  11.  
  12. /* last modified 03/11/98 */
  13. /*
  14. ********************************************************************************
  15. *                                                                              *
  16. *   LearnBook() is used to accumulate the evaluations for the first N moves    *
  17. *   out of book.  after these moves have been played, the evaluations are then *
  18. *   used to decide whether the last book move played was a reasonable choice   *
  19. *   or not.  (N is set by the #define LEARN_INTERVAL definition.)              *
  20. *                                                                              *
  21. *   there are three cases to be handled.  (1) if the evaluation is bad right   *
  22. *   out of book, or it drops enough to be considered a bad line, then the book *
  23. *   move will have its "learn" value reduced to discourage playing this move   *
  24. *   again.  (2) if the evaluation is even after N moves, then the learn        *
  25. *   value will be increased, but by a relatively modest amount, so that a few  *
  26. *   even results will offset one bad result.  (3) if the evaluation is very    *
  27. *   good after N moves, the learn value will be increased by a large amount    *
  28. *   so that this move will be favored the next time the game is played.        *
  29. *                                                                              *
  30. ********************************************************************************
  31. */
  32.  
  33. void LearnBook(TREE *tree, int wtm, int search_value, int search_depth, int lv,
  34.                int force) {
  35. /*
  36.  ----------------------------------------------------------
  37. |                                                          |
  38. |   if we have not been "out of book" for N moves, all     |
  39. |   we need to do is take the search evaluation for the    |
  40. |   search just completed and tuck it away in the book     |
  41. |   learning array (book_learn_eval[]) for use later.      |
  42. |                                                          |
  43.  ----------------------------------------------------------
  44. */
  45.   int t_wtm=wtm;
  46.   if (!book_file) return;
  47.   if (!(learning&book_learning)) return;
  48.   if (moves_out_of_book <= LEARN_INTERVAL && !force) {
  49.     if (moves_out_of_book) {
  50.       book_learn_eval[moves_out_of_book-1]=search_value;
  51.       book_learn_depth[moves_out_of_book-1]=search_depth;
  52.     }
  53.   }
  54. /*
  55.  ----------------------------------------------------------
  56. |                                                          |
  57. |   check the evaluations we've seen so far.  if they are  |
  58. |   within reason (+/- 1/3 of a pawn or so) we simply keep |
  59. |   playing and leave the book alone.  if the eval is much |
  60. |   better or worse, we need to update the learning count. |
  61. |                                                          |
  62.  ----------------------------------------------------------
  63. */
  64.   else if (moves_out_of_book == LEARN_INTERVAL+1 || force) {
  65.     int move, i, j, learn_value, read;
  66.     int secs, interval, last_book_move=-1;
  67.     float temp_value;
  68.     char cmd[32], buff[80], *nextc;
  69.     int best_eval=-999999, best_eval_p=0;
  70.     int worst_eval=999999, worst_eval_p=0, save_wtm;
  71.     int best_after_worst_eval=-999999, worst_after_best_eval=999999;
  72.     struct tm *timestruct;
  73.     int n_book_moves[512];
  74.     float book_learn[512], t_learn_value;
  75.  
  76.     if (moves_out_of_book < 1) return;
  77.     Print(128,"LearnBook() executed\n");
  78.     learning&=~book_learning;
  79.     interval=Min(LEARN_INTERVAL,moves_out_of_book);
  80.     if (interval < 2)  return;
  81.  
  82.     for (i=0;i<interval;i++) {
  83.       if (book_learn_eval[i] > best_eval) {
  84.         best_eval=book_learn_eval[i];
  85.         best_eval_p=i;
  86.       }
  87.       if (book_learn_eval[i] < worst_eval) {
  88.         worst_eval=book_learn_eval[i];
  89.         worst_eval_p=i;
  90.       }
  91.     }
  92.     if (best_eval_p < interval-1) {
  93.       for (i=best_eval_p;i<interval;i++)
  94.         if (book_learn_eval[i] < worst_after_best_eval)
  95.           worst_after_best_eval=book_learn_eval[i];
  96.     }
  97.     else worst_after_best_eval=book_learn_eval[interval-1];
  98.  
  99.     if (worst_eval_p < interval-1) {
  100.       for (i=worst_eval_p;i<interval;i++)
  101.         if (book_learn_eval[i] > best_after_worst_eval)
  102.           best_after_worst_eval=book_learn_eval[i];
  103.     }
  104.     else best_after_worst_eval=book_learn_eval[interval-1];
  105.  
  106. #if defined(DEBUG)
  107.     Print(128,"Learning analysis ...\n");
  108.     Print(128,"worst=%d  best=%d  baw=%d  wab=%d\n",
  109.           worst_eval, best_eval, best_after_worst_eval, worst_after_best_eval);
  110.     for (i=0;i<interval;i++)
  111.       Print(128,"%d(%d) ",book_learn_eval[i],book_learn_depth[i]);
  112.     Print(128,"\n");
  113. #endif
  114.  
  115. /*
  116.  ----------------------------------------------------------
  117. |                                                          |
  118. |   we now have the best eval for the first N moves out    |
  119. |   of book, the worst eval for the first N moves out of   |
  120. |   book, and the worst eval that follows the best eval.   |
  121. |   this will be used to recognize the following cases of  |
  122. |   results that follow a book move:                       |
  123. |                                                          |
  124.  ----------------------------------------------------------
  125. */
  126. /*
  127.  ----------------------------------------------------------
  128. |                                                          |
  129. |   (1) the best score is very good, and it doesn't drop   |
  130. |   after following the game further.  this case detects   |
  131. |   those moves in book that are "good" and should be      |
  132. |   played whenever possible.                              |
  133. |                                                          |
  134.  ----------------------------------------------------------
  135. */
  136.     if (best_eval == best_after_worst_eval) {
  137.       learn_value=best_eval;
  138.       for (i=0;i<interval;i++)
  139.         if (learn_value == book_learn_eval[i])
  140.           search_depth=Max(search_depth,book_learn_depth[i]);
  141.     }
  142. /*
  143.  ----------------------------------------------------------
  144. |                                                          |
  145. |   (2) the worst score is bad, and doesn't improve any    |
  146. |   after the worst point, indicating that the book move   |
  147. |   chosen was "bad" and should be avoided in the future.  |
  148. |                                                          |
  149.  ----------------------------------------------------------
  150. */
  151.     else if (worst_eval == worst_after_best_eval) {
  152.       learn_value=worst_eval;
  153.       for (i=0;i<interval;i++)
  154.         if (learn_value == book_learn_eval[i])
  155.           search_depth=Max(search_depth,book_learn_depth[i]);
  156.     }
  157. /*
  158.  ----------------------------------------------------------
  159. |                                                          |
  160. |   (3) things seem even out of book and remain that way   |
  161. |   for N moves.  we will just average the 10 scores and   |
  162. |   use that as an approximation.                          |
  163. |                                                          |
  164.  ----------------------------------------------------------
  165. */
  166.     else {
  167.       learn_value=0;
  168.       search_depth=0;
  169.       for (i=0;i<interval;i++) {
  170.         learn_value+=book_learn_eval[i];
  171.         search_depth+=book_learn_depth[i];
  172.       }
  173.       learn_value/=interval;
  174.       search_depth/=interval;
  175.     }
  176.     if (lv) learn_value=search_value;
  177.     if (lv == 0)
  178.       learn_value=LearnFunction(learn_value,search_depth,
  179.                                 crafty_rating-opponent_rating,
  180.                                 learn_value<0);
  181.     else learn_value=search_value;
  182. /*
  183.  ----------------------------------------------------------
  184. |                                                          |
  185. |   first, we are going to find every book move in the     |
  186. |   game, and note how many alternatives there were at     |
  187. |   every book move.                                       |
  188. |                                                          |
  189.  ----------------------------------------------------------
  190. */
  191.     save_wtm=wtm;
  192.     InitializeChessBoard(&tree->position[0]);
  193.     for (i=0;i<512;i++) n_book_moves[i]=0;
  194.     wtm=1;
  195.     for (i=0;i<512;i++) {
  196.       int *mv, cluster, key, test;
  197.       BITBOARD common, temp_hash_key;
  198.  
  199.       n_book_moves[i]=0;
  200.       fseek(history_file,i*10,SEEK_SET);
  201.       strcpy(cmd,"");
  202.       read=fscanf(history_file,"%s",cmd);
  203.       if (read != 1) break;
  204.       if (strcmp(cmd,"pass")) {
  205.         move=InputMove(tree,cmd,0,wtm,1,0);
  206.         if (!move) break;
  207.         tree->position[1]=tree->position[0];
  208.         tree->last[1]=GenerateCaptures(tree, 1, wtm, tree->last[0]);
  209.         tree->last[1]=GenerateNonCaptures(tree, 1, wtm, tree->last[1]);
  210.         test=HashKey>>49;
  211.         fseek(book_file,test*sizeof(int),SEEK_SET);
  212.         fread(&key,sizeof(int),1,book_file);
  213.         if (key > 0) {
  214.           fseek(book_file,key,SEEK_SET);
  215.           fread(&cluster,sizeof(int),1,book_file);
  216.           fread(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  217.         }
  218.         else cluster=0;
  219.         for (mv=tree->last[0];mv<tree->last[1];mv++) {
  220.           common=And(HashKey,mask_16);
  221.           MakeMove(tree, 1,*mv,wtm);
  222.           temp_hash_key=Xor(HashKey,wtm_random[wtm]);
  223.           temp_hash_key=Or(And(temp_hash_key,Compl(mask_16)),common);
  224.           for (j=0;j<cluster;j++)
  225.             if (!Xor(temp_hash_key,book_buffer[j].position) &&
  226.                 book_buffer[j].learn > (float) LEARN_COUNTER_BAD/100.0) {
  227.                 n_book_moves[i]++;
  228.                 last_book_move=i;
  229.             }
  230.           UnMakeMove(tree, 1,*mv,wtm);
  231.         }
  232.         if (move) MakeMoveRoot(tree, move,wtm);
  233.       }
  234.       wtm=ChangeSide(wtm);
  235.     } 
  236. /*
  237.  ----------------------------------------------------------
  238. |                                                          |
  239. |   now we build a vector of book learning results.  we    |
  240. |   give every book move below the last point where there  |
  241. |   were alternatives 100% of the learned score.  We give  |
  242. |   the book move played at that point 100% of the learned |
  243. |   score as well.  then we divide the learned score by    |
  244. |   the number of alternatives, and propogate this score   |
  245. |   back until there was another alternative, where we do  |
  246. |   this again and again until we reach the top of the     |
  247. |   book tree.                                             |
  248.  ----------------------------------------------------------
  249. */
  250.     t_learn_value=((float) learn_value)/100.0;
  251.     for (i=511;i>=0;i--) {
  252.       book_learn[i]=t_learn_value;
  253.       if (n_book_moves[i] > 1) t_learn_value/=n_book_moves[i];
  254.     }
  255. /*
  256.  ----------------------------------------------------------
  257. |                                                          |
  258. |   finally, we run thru the book file and update each     |
  259. |   book move learned value based on the computation we    |
  260. |   calculated above.                                      |
  261. |                                                          |
  262.  ----------------------------------------------------------
  263. */
  264.     InitializeChessBoard(&tree->position[0]);
  265.     wtm=1;
  266.     for (i=0;i<512;i++) {
  267.       strcpy(cmd,"");
  268.       fseek(history_file,i*10,SEEK_SET);
  269.       strcpy(cmd,"");
  270.       read=fscanf(history_file,"%s",cmd);
  271.       if (read != 1) break;
  272.       if (strcmp(cmd,"pass")) {
  273.         move=InputMove(tree,cmd,0,wtm,1,0);
  274.         if (!move) break;
  275.         tree->position[1]=tree->position[0];
  276. /*
  277.  ----------------------------------------------------------
  278. |                                                          |
  279. |   now call LearnBookUpdate() to find this position in    |
  280. |   the book database and update the learn stuff.          |
  281. |                                                          |
  282.  ----------------------------------------------------------
  283. */
  284.         temp_value=book_learn[i];
  285.         if (wtm != crafty_is_white) temp_value*=-1;
  286.         LearnBookUpdate(tree, wtm, move, temp_value);
  287.         MakeMoveRoot(tree, move,wtm);
  288.       }
  289.       wtm=ChangeSide(wtm);
  290.     } 
  291. /*
  292.  ----------------------------------------------------------
  293. |                                                          |
  294. |   now update the "book.lrn" file so that this can be     |
  295. |   shared with other crafty users or else saved in case.  |
  296. |   the book must be re-built.                             |
  297. |                                                          |
  298.  ----------------------------------------------------------
  299. */
  300.     fprintf(book_lrn_file,"[White \"%s\"]\n",pgn_white);
  301.     fprintf(book_lrn_file,"[Black \"%s\"]\n",pgn_black);
  302.     secs=time(0);
  303.     timestruct=localtime((time_t*) &secs);
  304.     fprintf(book_lrn_file,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
  305.             timestruct->tm_mon+1,timestruct->tm_mday);
  306.     nextc=buff;
  307.     for (i=0;i<=last_book_move;i++) {
  308.       fseek(history_file,i*10,SEEK_SET);
  309.       strcpy(cmd,"");
  310.       read=fscanf(history_file,"%s",cmd);
  311.       if (read!=1) break;
  312.       if (strchr(cmd,' ')) *strchr(cmd,' ')=0;
  313.       sprintf(nextc," %s",cmd);
  314.       nextc=buff+strlen(buff);
  315.       if (nextc-buff > 60) {
  316.         fprintf(book_lrn_file,"%s\n",buff);
  317.         nextc=buff;
  318.         strcpy(buff,"");
  319.       }
  320.     }
  321.     fprintf(book_lrn_file,"%s {%d %d %d}\n",
  322.             buff, (t_wtm) ? learn_value:-learn_value, search_depth,
  323.             crafty_rating-opponent_rating);
  324.     fflush(book_lrn_file);
  325. /*
  326.  ----------------------------------------------------------
  327. |                                                          |
  328. |   done.  now restore the game back to where it was       |
  329. |   before we started all this nonsense.  :)               |
  330. |                                                          |
  331.  ----------------------------------------------------------
  332. */
  333.     RestoreGame();
  334.   }
  335. }
  336.  
  337. /* last modified 03/11/98 */
  338. /*
  339. ********************************************************************************
  340. *                                                                              *
  341. *   LearnBookUpdate() is called to find the current position in the book and   *
  342. *   update the learn counter.  if it is supposed to mark a move as not to be   *
  343. *   played, and after marking such a move there are no more left at this point *
  344. *   in the database, it returns (0) which will force LearnBook() to back up    *
  345. *   two plies and update that position as well, since no more choices at the   *
  346. *   current position doesn't really do much for us...                          *
  347. *                                                                              *
  348. ********************************************************************************
  349. */
  350. void LearnBookUpdate(TREE *tree, int wtm, int move, float learn_value) {
  351.   int cluster, test, move_index, key;
  352.   BITBOARD temp_hash_key, common;
  353. /*
  354.  ----------------------------------------------------------
  355. |                                                          |
  356. |   first find the appropriate cluster, make the move we   |
  357. |   were passed, and find the resulting position in the    |
  358. |   database.                                              |
  359. |                                                          |
  360.  ----------------------------------------------------------
  361. */
  362.   test=HashKey>>49;
  363.   if (book_file) {
  364.     fseek(book_file,test*sizeof(int),SEEK_SET);
  365.     fread(&key,sizeof(int),1,book_file);
  366.     if (key > 0) {
  367.       fseek(book_file,key,SEEK_SET);
  368.       fread(&cluster,sizeof(int),1,book_file);
  369.       fread(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  370.       common=And(HashKey,mask_16);
  371.       MakeMove(tree, 1,move,wtm);
  372.       temp_hash_key=Xor(HashKey,wtm_random[wtm]);
  373.       temp_hash_key=Or(And(temp_hash_key,Compl(mask_16)),common);
  374.       for (move_index=0;move_index<cluster;move_index++)
  375.         if (!Xor(temp_hash_key,book_buffer[move_index].position)) break;
  376.       UnMakeMove(tree, 1,move,wtm);
  377.       if (move_index >= cluster) return;
  378.       if (book_buffer[move_index].learn == 0.0)
  379.         book_buffer[move_index].learn=learn_value;
  380.       else
  381.         book_buffer[move_index].learn=
  382.           (book_buffer[move_index].learn+learn_value)/2.0;
  383.       fseek(book_file,key+sizeof(int),SEEK_SET);
  384.       fwrite(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  385.       fflush(book_file);
  386.     }
  387.   }
  388. }
  389.  
  390. /* last modified 03/11/98 */
  391. /*
  392. ********************************************************************************
  393. *                                                                              *
  394. *   LearnFunction() is called to compute the adjustment value added to the     *
  395. *   learn counter in the opening book.  it takes three pieces of information   *
  396. *   into consideration to do this:  the search value, the search depth that    *
  397. *   produced this value, and the rating difference (Crafty-opponent) so that   *
  398. *   + numbers means Crafty is expected to win, - numbers mean Crafty is ex-    *
  399. *   pected to lose.                                                            *
  400. *                                                                              *
  401. ********************************************************************************
  402. */
  403. int LearnFunction(int sv, int search_depth, int rating_difference,
  404.                   int trusted_value) {
  405.   float rating_multiplier_trusted[11] = {.00625, .0125, .025, .05, .075, .1,
  406.                                          0.15, 0.2, 0.25, 0.3, 0.35};
  407.   float rating_multiplier_untrusted[11] = {.25, .2, .15, .1, .05, .025, .012,
  408.                                            .006, .003, .001};
  409.   float multiplier;
  410.   int sd, rd;
  411.  
  412.   sd=Max(Min(search_depth,19),0);
  413.   rd=Max(Min(rating_difference/200,5),-5)+5;
  414.   if (trusted_value)
  415.     multiplier=rating_multiplier_trusted[rd]*sd;
  416.   else
  417.     multiplier=rating_multiplier_untrusted[rd]*sd;
  418.   sv=Max(Min(sv,600),-600);
  419.   return(sv*multiplier);
  420. }
  421.  
  422. /* last modified 03/11/98 */
  423. /*
  424. ********************************************************************************
  425. *                                                                              *
  426. *  LearnImport() is used to read in a learn data file (*.lrn) and apply        *
  427. *  it to either book.bin (book.lrn file) or position.bin (position.lrn file).  *
  428. *  this allows users to create a new book.bin at any time, adding more games   *
  429. *  as needed, without losing all of the "learned" openings in the database.    *
  430. *                                                                              *
  431. *  the second intent is to allow users to "share" *.lrn files, and to allow me *
  432. *  to keep several of them on the ftp machine, so that anyone can use those    *
  433. *  file(s) and have their version of Crafty (or any other program that wants   *
  434. *  to participate in this) "learn" what other crafty's have already found out  *
  435. *  about which openings and positions are good and bad.                        *
  436. *                                                                              *
  437. *  the basic idea is to (a) stuff each book opening line into the game history *
  438. *  for LearnBook(), then set things up so that LearnBook() can be called and   *
  439. *  it will behave just as though this book line was just "learned".  if the    *
  440. *  file is a position.lrn type of file (which is recognized by finding a       *
  441. *  "setboard" command in the file as well as the word "position" in the first  *
  442. *  eight bytes of the file, then the positions and scores are read in and      *
  443. *  added to the position.bin file.                                             *
  444. *                                                                              *
  445. ********************************************************************************
  446. */
  447. void LearnImport(TREE *tree, int nargs, char **args) {
  448.  
  449.   FILE *learn_in;
  450.   char text[128];
  451.   int eof;
  452.  
  453. /*
  454.  ----------------------------------------------------------
  455. |                                                          |
  456. |   first, get the name of the file that contains the      |
  457. |   learned book lines.                                    |
  458. |                                                          |
  459.  ----------------------------------------------------------
  460. */
  461.   display_options&=4095-128;
  462.   learn_in=fopen(*args,"r");
  463.   if (learn_in == NULL) {
  464.     Print(4095,"unable to open %s for input\n", *args);
  465.     return;
  466.   }
  467.   eof=fscanf(learn_in,"%s",text);
  468.   fclose(learn_in);
  469.   if  (eof == 0) return;
  470.   if (!strcmp(text,"position")) LearnImportPosition(tree,nargs,args);
  471.   else LearnImportBook(tree,nargs,args);
  472. }
  473.  
  474. /* last modified 03/11/98 */
  475. /*
  476. ********************************************************************************
  477. *                                                                              *
  478. *   LearnImportBook() is used to import book learning and save it in the       *
  479. *   book.bin file (see LearnBook for details.)                                 *
  480. *                                                                              *
  481. ********************************************************************************
  482. */
  483.  
  484. #if defined(MACOS)
  485.   int index[32768];
  486. #endif
  487.  
  488. void LearnImportBook(TREE *tree, int nargs, char **args) {
  489.  
  490.   FILE *learn_in;
  491.   char nextc, text[128], *eof;
  492.   int wtm, learn_value, depth, rating_difference, move=0, i, added_lines=0;
  493.  
  494. /*
  495.  ----------------------------------------------------------
  496. |                                                          |
  497. |   if the <clear> option was given, first we cycle thru   |
  498. |   the entire book and clear every learned value.         |
  499. |                                                          |
  500.  ----------------------------------------------------------
  501. */
  502.   learn_in = fopen(args[0],"r");
  503.   if (nargs>1 && !strcmp(args[1],"clear")) {
  504. #if defined(MACOS)
  505.     int i, j, cluster;
  506. #else
  507.     int index[32768], i, j, cluster;
  508. #endif
  509.     fclose(book_lrn_file);
  510. #if defined(MACOS)
  511.     sprintf(text,":%s:book.lrn",book_path);
  512. #else
  513.     sprintf(text,"%s/book.lrn",book_path);
  514. #endif
  515.     book_lrn_file=fopen(text,"w");
  516.     fseek(book_file,0,SEEK_SET);
  517.     fread(index,sizeof(int),32768,book_file);
  518.     for (i=0;i<32768;i++)
  519.       if (index[i] > 0) {
  520.         fseek(book_file,index[i],SEEK_SET);
  521.         fread(&cluster,sizeof(int),1,book_file);
  522.         fread(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  523.         for (j=0;j<cluster;j++) book_buffer[j].learn=0.0;
  524.         fseek(book_file,index[i]+sizeof(int),SEEK_SET);
  525.         fwrite(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  526.       }
  527.   }
  528. /*
  529.  ----------------------------------------------------------
  530. |                                                          |
  531. |   outer loop loops thru the games (opening lines) one by |
  532. |   one, while the inner loop stuffs the game history file |
  533. |   with moves that were played.  the series of moves in a |
  534. |   line is terminated by the {x y z} data values.         |
  535. |                                                          |
  536.  ----------------------------------------------------------
  537. */
  538.   while (1) {
  539.     if (added_lines%10==0) {
  540.       printf(".");
  541.       fflush(stdout);
  542.     }
  543.     if ((added_lines+1)%600 == 0) printf(" (%d)\n",added_lines+1);
  544.     InitializeChessBoard(&tree->position[0]);
  545.     wtm=0;
  546.     move_number=0;
  547.     for (i=0;i<100;i++) {
  548.       fseek(history_file,i*10,SEEK_SET);
  549.       fprintf(history_file,"         \n");
  550.     }
  551.     for (i=0;i<3;i++) {
  552.       eof=fgets(text,80,learn_in);
  553.       if (eof) {
  554.         char *delim;
  555.         delim=strchr(text,'\n');
  556.         if (delim) *delim=0;
  557.         delim=strchr(text,'\r');
  558.         if (delim) *delim=' ';
  559.       }
  560.       else break;
  561.       if (strchr(text,'[')) do {
  562.         char *bracket1, *bracket2;
  563.         char value[32];
  564.   
  565.         bracket1=strchr(text,'\"');
  566.         bracket2=strchr(bracket1+1,'\"');
  567.         if (bracket1 == 0 || bracket2 == 0) break;
  568.         *bracket2=0;
  569.         strcpy(value,bracket1+1);
  570.         if (bracket2 == 0) break;
  571.         if (strstr(text,"White")) strcpy(pgn_white,value);
  572.         if (strstr(text,"Black")) strcpy(pgn_black,value);
  573.       } while(0);
  574.     }
  575.     if (eof == 0) break;
  576.     do {
  577.       wtm=ChangeSide(wtm);
  578.       if (wtm) move_number++;
  579.       do {
  580.         nextc=fgetc(learn_in);
  581.       } while(nextc == ' ' || nextc == '\n');
  582.       if (nextc == '{') break;
  583.       ungetc(nextc,learn_in);
  584.       move=ReadChessMove(tree,learn_in,wtm,1);
  585.       if (move < 0) break;
  586.       strcpy(text,OutputMove(tree,move,0,wtm));
  587.       fseek(history_file,((move_number-1)*2+1-wtm)*10,SEEK_SET);
  588.       fprintf(history_file,"%9s\n",text);
  589.       moves_out_of_book=0;
  590.       MakeMoveRoot(tree, move,wtm);
  591.     } while (1);
  592.     if (move < 0) break;
  593.     fscanf(learn_in,"%d %d %d}\n",&learn_value, &depth, &rating_difference);
  594.     moves_out_of_book=LEARN_INTERVAL+1;
  595.     move_number+=LEARN_INTERVAL+1-wtm;
  596.     for (i=0;i<LEARN_INTERVAL;i++) book_learn_eval[i]=learn_value;
  597.     crafty_rating=rating_difference;
  598.     opponent_rating=0;
  599.     learning|=book_learning;
  600.     if (abs(learn_value) != 99900)
  601.       LearnBook(tree, wtm, (wtm) ? learn_value : -learn_value, depth, 1, 1);
  602.     else
  603.       LearnResult(tree, learn_value < 0);
  604.     added_lines++;
  605.   }
  606.   move_number=1;
  607.   Print(4095,"\nadded %d learned book lines to book.bin\n",added_lines);
  608. }
  609.  
  610. /* last modified 03/11/98 */
  611. /*
  612. ********************************************************************************
  613. *                                                                              *
  614. *   LearnImportPosition() is used to import positions and save them in the     *
  615. *   position.bin file.  (see LearnPosition for details.)                       *
  616. *                                                                              *
  617. ********************************************************************************
  618. */
  619. void LearnImportPosition(TREE *tree, int nargs, char **args) {
  620.  
  621.   BITBOARD word1, word2;
  622.   int positions, nextp, secs;
  623.   struct tm *timestruct;
  624.   char xlate[15]={'q','r','b',0,'k','n','p',0,'P','N','K',0,'B','R','Q'};
  625.   char empty[9]={' ','1','2','3','4','5','6','7','8'};
  626.   int i, rank, file, nempty, value, move, depth, added_positions=0;
  627.   char *eof, text[80];
  628.   FILE *learn_in;
  629.  
  630. /*
  631.  ----------------------------------------------------------
  632. |                                                          |
  633. |   open the input file and skip the "position" signature, |
  634. |   since we know it's a position.lrn file because we are  |
  635. |   *here*.                                                |
  636. |                                                          |
  637.  ----------------------------------------------------------
  638. */
  639.   learn_in = fopen(args[0],"r");
  640.   eof=fgets(text,80,learn_in);
  641.   if (eof) {
  642.     char *delim;
  643.     delim=strchr(text,'\n');
  644.     if (delim) *delim=0;
  645.     delim=strchr(text,'\r');
  646.     if (delim) *delim=' ';
  647.   }
  648.   if (nargs>1 && !strcmp(args[1],"clear")) {
  649.     fclose(position_file);
  650. #if defined(MACOS)
  651.     sprintf(text,":%s:position.lrn",book_path);
  652. #else
  653.     sprintf(text,"%s/position.lrn",book_path);
  654. #endif
  655.     position_lrn_file=fopen(text,"w");
  656.     if (!position_lrn_file) {
  657. #if defined(MACOS)
  658.       printf("unable to open position learning file [:%s:position.lrn].\n",
  659.              book_path);
  660. #else
  661.       printf("unable to open position learning file [%s/position.lrn].\n",
  662.              book_path);
  663. #endif
  664.       return;
  665.     }
  666.     fprintf(position_lrn_file,"position\n");
  667. #if defined(MACOS)
  668.     sprintf(text,":%s:position.bin",book_path);
  669. #else
  670.     sprintf(text,"%s/position.bin",book_path);
  671. #endif
  672.     position_file=fopen(text,"wb+");
  673.     if (position_file) {
  674.       i=0;
  675.       fseek(position_file,0,SEEK_SET);
  676.       fwrite(&i,sizeof(int),1,position_file);
  677.       i--;
  678.       fwrite(&i,sizeof(int),1,position_file);
  679.     }
  680.     else {
  681. #if defined(MACOS)
  682.       printf("unable to open position learning file [:%s:position.bin].\n",
  683.              book_path);
  684. #else
  685.       printf("unable to open position learning file [%s/position.bin].\n",
  686.              book_path);
  687. #endif
  688.       return;
  689.     }
  690.   }
  691. /*
  692.  ----------------------------------------------------------
  693. |                                                          |
  694. |   loop through the file, reading in 5 records at a time, |
  695. |   the White, Black, Date PGN tags, the setboard FEN, and |
  696. |   the search value/depth to store.                       |
  697. |                                                          |
  698.  ----------------------------------------------------------
  699. */
  700.   while (1) {
  701.     for (i=0;i<3;i++) {
  702.       eof=fgets(text,80,learn_in);
  703.       if (eof) {
  704.         char *delim;
  705.         delim=strchr(text,'\n');
  706.         if (delim) *delim=0;
  707.         delim=strchr(text,'\r');
  708.         if (delim) *delim=' ';
  709.       }
  710.       else break;
  711.       if (strchr(text,'[')) do {
  712.         char *bracket1, *bracket2;
  713.         char value[32];
  714.   
  715.         bracket1=strchr(text,'\"');
  716.         bracket2=strchr(bracket1+1,'\"');
  717.         if (bracket1 == 0 || bracket2 == 0) break;
  718.         *bracket2=0;
  719.         strcpy(value,bracket1+1);
  720.         if (bracket2 == 0) break;
  721.         if (strstr(text,"White")) strcpy(pgn_white,value);
  722.         if (strstr(text,"Black")) strcpy(pgn_black,value);
  723.       } while(0);
  724.     }
  725.     if (eof == 0) break;
  726.     eof=fgets(text,80,learn_in);
  727.     if (eof) {
  728.       char *delim;
  729.       delim=strchr(text,'\n');
  730.       if (delim) *delim=0;
  731.       delim=strchr(text,'\r');
  732.       if (delim) *delim=' ';
  733.     }
  734.     nargs=ReadParse(text,args,"     ;\n");
  735.     if (strcmp(args[0],"setboard"))
  736.       Print(4095,"ERROR.  missing setboard command in file.\n");
  737.     SetBoard(nargs-1,args+1,0);
  738.     eof=fgets(text,80,learn_in);
  739.     if (eof) {
  740.       char *delim;
  741.       delim=strchr(text,'\n');
  742.       if (delim) *delim=0;
  743.       delim=strchr(text,'\r');
  744.       if (delim) *delim=' ';
  745.     }
  746.     else break;
  747.     nargs=ReadParse(text+1,args,"     ,;{}\n");
  748.     value=atoi(args[0]);
  749.     move=atoi(args[1]);
  750.     depth=atoi(args[2]);
  751. /*
  752.  ----------------------------------------------------------
  753. |                                                          |
  754. |   now "fill in the blank" and build a table entry from   |
  755. |   current search information.                            |
  756. |                                                          |
  757.  ----------------------------------------------------------
  758. */
  759.     if (abs(value) < MATE-100)
  760.       word1=Shiftl((BITBOARD) (value+65536),43);
  761.     else if (value > 0)
  762.       word1=Shiftl((BITBOARD) (value+65536),43);
  763.     else
  764.       word1=Shiftl((BITBOARD) (value+65536),43);
  765.     word1=Or(word1,Shiftl((BITBOARD) wtm,63));
  766.     word1=Or(word1,Shiftl((BITBOARD) move,16));
  767.     word1=Or(word1,(BITBOARD) depth);
  768.   
  769.     word2=HashKey;
  770.  
  771.     fseek(position_file,0,SEEK_SET);
  772.     fread(&positions,sizeof(int),1,position_file);
  773.     fread(&nextp,sizeof(int),1,position_file);
  774.     if (positions < 65536) positions++;
  775.     fseek(position_file,0,SEEK_SET);
  776.     fwrite(&positions,sizeof(int),1,position_file);
  777.     nextp++;
  778.     if (nextp == 65536) nextp=0;
  779.     fwrite(&nextp,sizeof(int),1,position_file);
  780.     fseek(position_file,2*(nextp-1)*sizeof(BITBOARD)+2*sizeof(int),SEEK_SET);
  781.     fwrite(&word1,sizeof(BITBOARD),1,position_file);
  782.     fwrite(&word2,sizeof(BITBOARD),1,position_file);
  783.     added_positions++;
  784. /*
  785.  ----------------------------------------------------------
  786. |                                                          |
  787. |   now update the position.lrn file so that the position  |
  788. |   is saved in a form that can be imported later in other |
  789. |   versions of crafty on different machines.              |
  790. |                                                          |
  791.  ----------------------------------------------------------
  792. */
  793.     fprintf(position_lrn_file,"[Black \"%s\"]\n",pgn_white);
  794.     fprintf(position_lrn_file,"[White \"%s\"]\n",pgn_black);
  795.     secs=time(0);
  796.     timestruct=localtime((time_t*) &secs);
  797.     fprintf(position_lrn_file,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
  798.             timestruct->tm_mon+1,timestruct->tm_mday);
  799.     fprintf(position_lrn_file,"setboard ");
  800.     for (rank=RANK8;rank>=RANK1;rank--) {
  801.       nempty=0;
  802.       for (file=FILEA;file<=FILEH;file++) {
  803.         if (PieceOnSquare((rank<<3)+file)) {
  804.           if (nempty) {
  805.             fprintf(position_lrn_file,"%c",empty[nempty]);
  806.             nempty=0;
  807.           }
  808.           fprintf(position_lrn_file,"%c",xlate[PieceOnSquare((rank<<3)+file)+7]);
  809.         }
  810.         else nempty++;
  811.       }
  812.       fprintf(position_lrn_file,"/");
  813.     }
  814.     fprintf(position_lrn_file," %c ",(wtm)?'w':'b');
  815.     if (WhiteCastle(0) & 1) fprintf(position_lrn_file,"K");
  816.     if (WhiteCastle(0) & 2) fprintf(position_lrn_file,"Q");
  817.     if (BlackCastle(0) & 1) fprintf(position_lrn_file,"k");
  818.     if (BlackCastle(0) & 2) fprintf(position_lrn_file,"q");
  819.     if (EnPassant(0)) fprintf(position_lrn_file," %c%c",File(EnPassant(0))+'a',
  820.                               Rank(EnPassant(0))+((wtm)?-1:+1)+'1');
  821.     fprintf(position_lrn_file,"\n{%d %d %d}\n",value,move,depth);
  822.   }
  823.   Print(4095,"added %d new positions to position.bin\n",added_positions);
  824.   Print(4095,"      %d total positions in position.bin\n",positions);
  825.   fflush(position_file);
  826.   fflush(position_lrn_file);
  827. }
  828.  
  829. /* last modified 03/11/98 */
  830. /*
  831. ********************************************************************************
  832. *                                                                              *
  833. *   LearnPosition() is the driver for the second phase of Crafty's learning    *
  834. *   code.  this procedure takes the result of selected (or all) searches that  *
  835. *   are done during a game and stores them in a permanent hash table that is   *
  836. *   kept on disk.  before a new search begins, the values in this permanent    *
  837. *   file are copied to the active transposition table, so that the values will *
  838. *   be accessible a few plies earlier than in the game where the positions     *
  839. *   were learned.                                                              *
  840. *                                                                              *
  841. *     bits     name  SL  description                                           *
  842. *       1       wtm  63  used to control which transposition table gets this   *
  843. *                        position.                                             *
  844. *      19     value  43  unsigned integer value of this position + 65536.      *
  845. *                        this might be a good score or search bound.           *
  846. *      21      move  16  best move from the current position, according to the *
  847. *                        search at the time this position was stored.          *
  848. *                                                                              *
  849. *      16     draft   0  the depth of the search below this position, which is *
  850. *                        used to see if we can use this entry at the current   *
  851. *                        position.  note that this is in units of 1/60th of a  *
  852. *                        ply.                                                  *
  853. *      64       key   0  complete 64bit hash key.                              *
  854. *                                                                              *
  855. *    the file will, by default, hold 65536 learned positions.  the first word  *
  856. *  indicates how many positions are actually stored in the file, while the     *
  857. *  second word points to the overwrite point.  once the file reaches the max   *
  858. *  size, this overwrite point will wrap to the beginning so that the file will *
  859. *  always contain the most recent 64K positions.                               *
  860. *                                                                              *
  861. ********************************************************************************
  862. */
  863. void LearnPosition(TREE *tree, int wtm, int last_value, int value) {
  864.   BITBOARD word1, word2;
  865.   int positions, nextp, secs;
  866.   struct tm *timestruct;
  867.   char xlate[15]={'q','r','b',0,'k','n','p',0,'P','N','K',0,'B','R','Q'};
  868.   char empty[9]={' ','1','2','3','4','5','6','7','8'};
  869.   int rank, file, nempty;
  870. /*
  871.  ----------------------------------------------------------
  872. |                                                          |
  873. |   is there anything to learn?  if we are already behind  |
  874. |   a significant amount, losing more is not going to help |
  875. |   learning.  otherwise if the score drops by 1/3 of a    |
  876. |   pawn, remember the position.  if we are way out of the |
  877. |   book, learning won't help either, as the position will |
  878. |   not likely show up again.                              |
  879. |                                                          |
  880.  ----------------------------------------------------------
  881. */
  882.   if ((!position_lrn_file) || (!position_file)) return;
  883.   if (last_value < -2*PAWN_VALUE) return;
  884.   if (last_value < value+PAWN_VALUE/3) return;
  885.   if (moves_out_of_book > 10) return;
  886. /*
  887.  ----------------------------------------------------------
  888. |                                                          |
  889. |   now "fill in the blank" and build a table entry from   |
  890. |   current search information.                            |
  891. |                                                          |
  892.  ----------------------------------------------------------
  893. */
  894.   Print(4095,"learning position, wtm=%d  value=%d\n",wtm,value);
  895.   word1=Shiftl((BITBOARD) (value+65536),43);
  896.   word1=Or(word1,Shiftl((BITBOARD) wtm,63));
  897.   word1=Or(word1,Shiftl((BITBOARD) tree->pv[0].path[1],16));
  898.   word1=Or(word1,(BITBOARD) (tree->pv[0].path_iteration_depth*INCREMENT_PLY-INCREMENT_PLY));
  899.  
  900.   
  901.   word2=HashKey;
  902.  
  903.   fseek(position_file,0,SEEK_SET);
  904.   fread(&positions,sizeof(int),1,position_file);
  905.   fread(&nextp,sizeof(int),1,position_file);
  906.   if (positions < 65536) positions++;
  907.   fseek(position_file,0,SEEK_SET);
  908.   fwrite(&positions,sizeof(int),1,position_file);
  909.   nextp++;
  910.   if (nextp == 65536) nextp=0;
  911.   fwrite(&nextp,sizeof(int),1,position_file);
  912.   fseek(position_file,2*nextp*sizeof(BITBOARD)+2*sizeof(int),SEEK_SET);
  913.   fwrite(&word1,sizeof(BITBOARD),1,position_file);
  914.   fwrite(&word2,sizeof(BITBOARD),1,position_file);
  915.   fflush(position_file);
  916. /*
  917.  ----------------------------------------------------------
  918. |                                                          |
  919. |   now update the position.lrn file so that the position  |
  920. |   is saved in a form that can be imported later in other |
  921. |   versions of crafty on different machines.              |
  922. |                                                          |
  923.  ----------------------------------------------------------
  924. */
  925.   fprintf(position_lrn_file,"[Black \"%s\"]\n",pgn_white);
  926.   fprintf(position_lrn_file,"[White \"%s\"]\n",pgn_black);
  927.   secs=time(0);
  928.   timestruct=localtime((time_t*) &secs);
  929.   fprintf(position_lrn_file,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
  930.           timestruct->tm_mon+1,timestruct->tm_mday);
  931.   fprintf(position_lrn_file,"setboard ");
  932.   for (rank=RANK8;rank>=RANK1;rank--) {
  933.     nempty=0;
  934.     for (file=FILEA;file<=FILEH;file++) {
  935.       if (PieceOnSquare((rank<<3)+file)) {
  936.         if (nempty) {
  937.           fprintf(position_lrn_file,"%c",empty[nempty]);
  938.           nempty=0;
  939.         }
  940.         fprintf(position_lrn_file,"%c",xlate[PieceOnSquare((rank<<3)+file)+7]);
  941.       }
  942.       else nempty++;
  943.     }
  944.     fprintf(position_lrn_file,"/");
  945.   }
  946.   fprintf(position_lrn_file," %c ",(wtm)?'w':'b');
  947.   if (WhiteCastle(0) & 1) fprintf(position_lrn_file,"K");
  948.   if (WhiteCastle(0) & 2) fprintf(position_lrn_file,"Q");
  949.   if (BlackCastle(0) & 1) fprintf(position_lrn_file,"k");
  950.   if (BlackCastle(0) & 2) fprintf(position_lrn_file,"q");
  951.   if (EnPassant(0)) fprintf(position_lrn_file," %c%c",File(EnPassant(0))+'a',
  952.                             Rank(EnPassant(0))+'1');
  953.   fprintf(position_lrn_file,"\n{%d %d %d}\n",value,
  954.           tree->pv[0].path[1],
  955.           tree->pv[0].path_iteration_depth*INCREMENT_PLY);
  956.   fflush(position_lrn_file);
  957. }
  958.  
  959. /* last modified 03/11/98 */
  960. /*
  961. ********************************************************************************
  962. *                                                                              *
  963. *   simply read from the learn.bin file, and stuffed into the correct table.   *
  964. *                                                                              *
  965. ********************************************************************************
  966. */
  967. void LearnPositionLoad(TREE *tree) {
  968.   register BITBOARD temp_hash_key;
  969.   BITBOARD word1, word2, worda, wordb;
  970.   register HASH_ENTRY *htable;
  971.   int n, positions;
  972. /*
  973.  ----------------------------------------------------------
  974. |                                                          |
  975. |   If position learning file not accessible: exit.  also, |
  976. |   if the time/move is very short, skip this.             |
  977. |                                                          |
  978.  ----------------------------------------------------------
  979. */
  980.   if (!position_file) return; 
  981.   if (time_limit < 100) return;
  982. /*
  983.  ----------------------------------------------------------
  984. |                                                          |
  985. |   first, find out how many learned positions are in the  |
  986. |   file and set up to start reading/stuffing them.        |
  987. |                                                          |
  988.  ----------------------------------------------------------
  989. */
  990.   if (moves_out_of_book >= 10) return;
  991.   fseek(position_file,0,SEEK_SET);
  992.   fread(&positions,sizeof(int),1,position_file);
  993.   fseek(position_file,2*sizeof(int),SEEK_SET);
  994. /*
  995.  ----------------------------------------------------------
  996. |                                                          |
  997. |   first, find out how many learned positions are in the  |
  998. |   file and set up to start reading/stuffing them.        |
  999. |                                                          |
  1000.  ----------------------------------------------------------
  1001. */
  1002.   for (n=0;n<positions;n++) {
  1003.     fread(&word1,sizeof(BITBOARD),1,position_file);
  1004.     fread(&word2,sizeof(BITBOARD),1,position_file);
  1005.     temp_hash_key=word2;
  1006.     htable=((Shiftr(word1,63)) ? trans_ref_wa : trans_ref_ba)+
  1007.       (((int) temp_hash_key)&hash_maska);
  1008.     temp_hash_key=temp_hash_key>>16;
  1009.     wordb=Shiftr(word2,16);
  1010.     wordb=Or(wordb,Shiftl(And(word1,mask_112),48));
  1011.  
  1012.     worda=Shiftl((BITBOARD) (Shiftr(word1,43) & 01777777),21);
  1013.     worda=Or(worda,Shiftl((BITBOARD) 3,59));
  1014.     htable->word1=worda;
  1015.     htable->word2=wordb;
  1016.   }
  1017. }
  1018.  
  1019. /* last modified 03/11/98 */
  1020. /*
  1021. ********************************************************************************
  1022. *                                                                              *
  1023. *   LearnResult() is used to learn from the result of a game that was played   *
  1024. *   to mate or resignation.  Crafty will use the result (if it lost the game)  *
  1025. *   to mark the book move made at the last position where it had more than one *
  1026. *   book move, so that that particular move won't be played again, just as if  *
  1027. *   the learned-value was extremely bad.                                       *
  1028. *                                                                              *
  1029. ********************************************************************************
  1030. */
  1031.  
  1032. void LearnResult(TREE *tree, int wtm) {
  1033.   int move, i, j;
  1034.   int secs, last_choice;
  1035.   char cmd[32], buff[80], *nextc;
  1036.   struct tm *timestruct;
  1037.   int n_book_moves[512];
  1038.   int t_wtm=wtm;
  1039. /*
  1040.  ----------------------------------------------------------
  1041. |                                                          |
  1042. |   first, we are going to find every book move in the     |
  1043. |   game, and note how many alternatives there were at     |
  1044. |   every book move.                                       |
  1045. |                                                          |
  1046.  ----------------------------------------------------------
  1047. */
  1048.   if (!book_file) return;
  1049.   if (!(learning & result_learning)) return;
  1050.   Print(128,"LearnResult() executed\n");
  1051.   learning&=~result_learning;
  1052.   InitializeChessBoard(&tree->position[0]);
  1053.   for (i=0;i<512;i++) n_book_moves[i]=0;
  1054.   wtm=1;
  1055.   for (i=0;i<512;i++) {
  1056.     int *mv, cluster, key, test;
  1057.     BITBOARD common, temp_hash_key;
  1058.  
  1059.     n_book_moves[i]=0;
  1060.     strcpy(cmd,"");
  1061.     fseek(history_file,i*10,SEEK_SET);
  1062.     fscanf(history_file,"%s",cmd);
  1063.     if (strcmp(cmd,"pass")) {
  1064.       move=InputMove(tree,cmd,0,wtm,1,0);
  1065.       if (!move) break;
  1066.       tree->position[1]=tree->position[0];
  1067.       tree->last[1]=GenerateCaptures(tree, 1, wtm, tree->last[0]);
  1068.       tree->last[1]=GenerateNonCaptures(tree, 1, wtm, tree->last[1]);
  1069.       test=HashKey>>49;
  1070.       fseek(book_file,test*sizeof(int),SEEK_SET);
  1071.       fread(&key,sizeof(int),1,book_file);
  1072.       if (key > 0) {
  1073.         fseek(book_file,key,SEEK_SET);
  1074.         fread(&cluster,sizeof(int),1,book_file);
  1075.         fread(book_buffer,sizeof(BOOK_POSITION),cluster,book_file);
  1076.       }
  1077.       else cluster=0;
  1078.       for (mv=tree->last[0];mv<tree->last[1];mv++) {
  1079.         common=And(HashKey,mask_16);
  1080.         MakeMove(tree, 1,*mv,wtm);
  1081.         temp_hash_key=Xor(HashKey,wtm_random[wtm]);
  1082.         temp_hash_key=Or(And(temp_hash_key,Compl(mask_16)),common);
  1083.         for (j=0;j<cluster;j++)
  1084.           if (!Xor(temp_hash_key,book_buffer[j].position) &&
  1085.               book_buffer[j].learn > (float) LEARN_COUNTER_BAD/100.0)
  1086.             n_book_moves[i]++;
  1087.         UnMakeMove(tree, 1,*mv,wtm);
  1088.       }
  1089.       if (move) MakeMoveRoot(tree, move,wtm);
  1090.     }
  1091.     wtm=ChangeSide(wtm);
  1092.   } 
  1093. /*
  1094.  ----------------------------------------------------------
  1095. |                                                          |
  1096. |   now, find the last book move where there was more than |
  1097. |   one alternative to choose from.                        |
  1098. |                                                          |
  1099.  ----------------------------------------------------------
  1100. */
  1101.   if (!t_wtm) {
  1102.     for (last_choice=511;last_choice>=0;last_choice-=2)
  1103.       if (n_book_moves[last_choice] > 1) break;
  1104.   }
  1105.   else {
  1106.     for (last_choice=510;last_choice>=0;last_choice-=2)
  1107.       if (n_book_moves[last_choice] > 1) break;
  1108.   }
  1109.   if (last_choice < 0) return;
  1110. /*
  1111.  ----------------------------------------------------------
  1112. |                                                          |
  1113. |   finally, we run thru the book file and update each     |
  1114. |   book move learned value based on the computation we    |
  1115. |   calculated above.                                      |
  1116. |                                                          |
  1117.  ----------------------------------------------------------
  1118. */
  1119.   InitializeChessBoard(&tree->position[0]);
  1120.   wtm=1;
  1121.   for (i=0;i<512;i++) {
  1122.     strcpy(cmd,"");
  1123.     fseek(history_file,i*10,SEEK_SET);
  1124.     strcpy(cmd,"");
  1125.     fscanf(history_file,"%s",cmd);
  1126.     if (strcmp(cmd,"pass")) {
  1127.       move=InputMove(tree,cmd,0,wtm,1,0);
  1128.       if (!move) break;
  1129.       tree->position[1]=tree->position[0];
  1130.       if (i == last_choice) LearnBookUpdate(tree, wtm, move, -999.0);
  1131.       MakeMoveRoot(tree, move,wtm);
  1132.     }
  1133.     wtm=ChangeSide(wtm);
  1134.   } 
  1135. /*
  1136.  ----------------------------------------------------------
  1137. |                                                          |
  1138. |   now update the "book.lrn" file so that this can be     |
  1139. |   shared with other crafty users or else saved in case.  |
  1140. |   the book must be re-built.                             |
  1141. |                                                          |
  1142.  ----------------------------------------------------------
  1143. */
  1144.   fprintf(book_lrn_file,"[White \"%s\"]\n",pgn_white);
  1145.   fprintf(book_lrn_file,"[Black \"%s\"]\n",pgn_black);
  1146.   secs=time(0);
  1147.   timestruct=localtime((time_t*) &secs);
  1148.   fprintf(book_lrn_file,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
  1149.           timestruct->tm_mon+1,timestruct->tm_mday);
  1150.   nextc=buff;
  1151.   for (i=0;i<=last_choice;i++) {
  1152.     fseek(history_file,i*10,SEEK_SET);
  1153.     fscanf(history_file,"%s",cmd);
  1154.     if (strchr(cmd,' ')) *strchr(cmd,' ')=0;
  1155.     sprintf(nextc," %s",cmd);
  1156.     nextc=buff+strlen(buff);
  1157.     if (nextc-buff > 60) {
  1158.       fprintf(book_lrn_file,"%s\n",buff);
  1159.       nextc=buff;
  1160.       strcpy(buff,"");
  1161.     }
  1162.   }
  1163.   fprintf(book_lrn_file,"%s {%d %d %d}\n",
  1164.           buff, (t_wtm) ? -99900:99900, 10, 0);
  1165.   fflush(book_lrn_file);
  1166. /*
  1167.  ----------------------------------------------------------
  1168. |                                                          |
  1169. |   done.  now restore the game back to where it was       |
  1170. |   before we started all this nonsense.  :)               |
  1171. |                                                          |
  1172.  ----------------------------------------------------------
  1173. */
  1174.   RestoreGame();
  1175. }
  1176.