Wisdom is knowing how

   little we know -- Socrates

About Company

Started in 1980, retired in 2004 REBEL was baptized into ProDeo, latin for gratis according to Dutch tradition.

Other Information

   Rybka-ICGA fiasco

 

 

  

 

 

 

 

    External links

 

 

 

 

 

 

FEN parsing and the accusation Vas copied that from Fruit

(beta version)

 

Mark Watkins

 

6.3.1 Parsing the "position" string

 

One example of copying seems to be in how Rybka parses the "position" string. 

 


 

Andrew Dalke is a software specialist who contacted me about the ICGA-Rybka case.

 

Andrew wrote me his findings.

 

The main issue is that Fruit contains:

 

   fen = strstr(string,"fen ");
   moves = strstr(string, "moves ");

   // start position

   if (fen != NULL) {                       // "fen" present

      if (moves != NULL) {               // "moves" present
         ASSERT(moves>fen);
         moves[-1] = '\0';                // dirty, but so is UCI
      }

      board_from_fen(SearchInput->board,fen+4);        // CHANGE ME

   } else {

      // HACK: assumes startpos

      board_from_fen(SearchInput->board,StartFen);
   }

  

Please note that the "else" clause was omitted in that PDF. The claimed translation in

http://www.chessvibes.com/plaatjes/rybkaevidence/RYBKA_FRUIT_Mar11.pdf

 

 v3 = strstr(a1, "fen");
  v1 = strstr(v2, "moves");
  sub_403490();    // board_from_fen(), for startpos
  if (v3)
  {  if (v1) {
       *(v1 - 1) = 0   // board_from_fen(FEN) -- maybe sub_403490(v3)?
     sub_403490();
  }

 

Nearly every line of this is different than the original:
  

  1. "fen" instead of "fen ".
     
  2. "moves" instead of "moves ".
     
  3. sub_403490 takes only one parameter, not two.
     
  4. sub_403490 always parses the "startpos" case, then resets the board if there is a fen (the Fruit case only does one or the other).

 

I do not know why the "else {...}" clause was omitted from the report, but its removal deemphasizes that the code expresses different logic.

 

An alternate translation, without fruitification, would be:

 
fen = strstr(s, "fen");
  moves = strstr(s, "moves");
  parse_fen(startpos);
  if (fen && moves) {
     moves[-1] = '\0';
     parse_fen(moves);
  }

 

This is a different looking code, even if the compiled version is similar, and does not justify a copyright claim.

 

The author says "In any case, the fact that "something is done" here that (in the end) serves no purpose makes this a mentionable commonality".

 

However, the author does not show evidence for that conclusion. While the Fruit code does not need a NUL terminated string (I checked), there is no evidence that that NUL serves no purpose in Rybka's fen parser.

 

In addition, that s[-1] = '\0' operation is somewhat unusual, but there are valid reasons for its use. Interestingly, it exists in one other spot in the Fruit code base [1], but the authors did not look t see if that idiom was duplicated in Rybka, nor did they check to see if Rybka had a pattern of using that idiom.

 

[1] Likely pointing to PROTOCOL.CPP (line 505)  value[-1] = '\0';



 

Some additional analysis

 

  1. For the start position the 2 old rivals are using different strings:
      
    FRUIT -  rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

          RYBKA - rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -

 

     2.  Using constructions like s[-1]= are not unusual, a quick search from my own engine

          gave 3 positive results:

 

          vb[-1]=0xff

          wpnum[-1]=9; wpnum[8]=9;

          zpnum[-1]=0;  zpnum[8]=0;

 

          In the above wpnum/zpnum case it's putting markers (sentinels) at the beginning and

          end of an array for faster code whether searching forwards or backwards. It will also avoid

          ending up with a classic system crash, exception error....

 

      3. However this case is about receiving an UCI string that oddly contains the FEN and the 

          MOVES in ONE string, hence Fabien's remark:

 

          moves[-1] = '\0';  // dirty, but so is UCI
   

          It makes from one string two strings FEN and MOVES now separately. A programmers
          convenience.

 

          Sven Schüle at Engine Origins

 

           Writing "moves[-1] = '\0'" or "*(moves - 1) = 0" (which is the same) in the given context does a

           very simple and clean thing: after having read the "moves" keyword coming right behind an FEN

           string, it null-terminates the FEN string part having been read previously in order to prepare the

           subsequent processing of the two independent sections: FEN string and "moves" section. This is

           simply CLEAN DESIGN, based on knowing that the "moves" section does not appear left from the

           FEN string (Fruit does an "ASSERT(moves>fen)" for this purpose). It allows to deal with the FEN

           string parsing itself fully independent from any trailing "garbage" that would have to be

           "ignored". A lot of simple parsers work like that, splitting a "physical" input string into "logical"

           pieces by inserting zero bytes at the appropriate dance figure.

 

           The Fruit comment "Dirty, but so is UCI" should not be interpreted as if this "moves[-1] = '\0'"

           were "quirky" somehow, it is just the straightforward way of doing it. Of course the notation

           using square brackets looks similar to using an array, and of course "*(moves - 1) = 0" would

           avoid such a misunderstanding, but it is essentially the same, standard way of implementing a

           split into parts. 

           I never understood why this statement has attracted so much attention within the Fruit/Rybka

           case. It is something on the same level as "*ptr++ = x". 

           Sven

 

       4.  More code differences

 

FRUIT

 

   if (moves != NULL) {

      ptr = moves + 6;

      while (*ptr != '\0') {

 

         move_string[0] = *ptr++;
         move_string[1] = *ptr++;
         move_string[2] = *ptr++;
         move_string[3] = *ptr++;

         if (*ptr == '\0' || *ptr == ' ') {           

           move_string[4] = '\0';
         } else { // promote
            move_string[4] = *ptr++;
            move_string[5] = '\0';
         }

  

       move = move_from_string(move_string,SearchInput->board);

 

 

      move_do(SearchInput->board,move,undo);

 

 

 

         while (*ptr == ' ') ptr++;
      }
   }

 

 

 

 

  return;

RYBKA

 

  if ( v2 )  {
    v4 = (int)(v2 + 6);
    while ( *(_BYTE *)v4 )   {

 

 


 

 

 

 

 

 

 

 

 

   v5 = sub_40AAF0(v4);   


 

 

   sub_40ABC0(v5);    

 

 


      v4 += 5;
      if ( !*(_BYTE *)(v4 - 1) )
        break;
      for ( ; *(_BYTE *)v4 == 32; ++v4 ) ;
    }
  }


  return sub_401100((int)&dword_667A90); 

COMMENTS

 

  when "moves"are  

  present in UCI do:
  
  
  The blue Fruit code not

  in  Rybka, at least not

  here.

 

 

 

 

 

 

  Note that  Fruit has

  two parameters, Rybka

  one.

    

  Make the move on the

  board.


 

  Get ready to receive

  the next move, stop

  searching if no more.


 

 

 


  This code is not in

  Fruit.

  No  idea what it does,

  probably initialization

  code for the new  

  position.

 

 

There are more differences but for the start of a discussion this will do for the moment.

 

 

To be continued some day

 

 

Update - September 2013, no further decompilation needed, nobody challenged the opposing findings.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Copyright ® 2012 Ed Schröder