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







Did Vasik really copied Fruit's time control ?

see protocol.cpp (line 229)

routine parse_go()


Mark Watkins

6.3.2 Time management


In this section, I largely refer to Rick Fadden's 32-bit Rybka 1.0 Beta disassembly

efforts at http://www.talkchess.com/forum/viewtopic.php?p=187290.


I find Fadden's decompilation to be very precise. For instance, he keeps all the variables (such as btime/wtime/binc/winc) in the same order as in the ASM code.



First of all we like to point out 3 errors in the reversed engineered Fadden code.


Handling "wtime" and "btime" doesn't mention 5 seconds (5000) are subtracted as the assembler shows


.text:0040961F                 mov     edi, offset aWtime ; "wtime"
.text:00409624                 mov     esi, ebp
.text:00409626                 mov     ecx, 6
.text:0040962B                 xor      eax, eax
.text:0040962D                 repe  cmpsb
.text:0040962F                 jnz       short loc_409653
.text:00409631                 push    offset asc_661F8C
.text:00409636                 push    ebx            
.text:00409637                 call     _strtok
.text:0040963C                 push    eax            
.text:0040963D                 call     j__atol
.text:00409642                 add     esp, 0Ch
.text:00409645                 sub     eax, 1388h                    ; 5000
.text:0040964A                 mov    [esp+2Ch+var_C], eax   ; wtime - 5000 (not in Fadden decompile)
.text:0040964E                 jmp     loc_4097AC                  ; FRUIT : wtime = double(atoi(ptr)) / 1000.0;

Same for "btime", Fadden only states:  


if (!strcmp (ptr,"btime")) { ptr = strtok (NULL," "); btime = atoi (ptr); 


And does not mention the 5000 subtraction.



The second error we notable find in the most discussed instruction of Rybka 1.0 case the notorious 0.0 comparison.


Mark Watkins - The subsequent lines in Fadden's Rybka 1.0 Beta decompilation have:


// Rybka compares movetime with a double precision value: 0.0

if (movetime >= 0.0) {

time_limit_1 = 5 * movetime;

time_limit_2 = 1000 * movetime;


However the assembler code tells us otherwise, the right interpreation of the code is not

if (movetime >= 0.0) but

if (movetime > 0.0) as the hex-rays decomplie also shows.


.text:004097E6                 fild       [esp+2Ch+var_14]        ;  if (movetime > 0.0)
.text:004097EA                 fcomp  ds:dbl_6623D0           
.text:004097F0                 fnstsw  ax                             

.text:004097F2                 test      ah, 41h                        ; test CO and C3 flags FPU status word
.text:004097F5                 jnz       short x10                     ; take jump when <=
.text:004097F7                 lea       ecx, [esi+esi*4]            ; time_limit_1 = 5 * movetime;
.text:004097FA                 imul     esi, 3E8h                      ; time_limit_2 = 1000 * movetime;
.text:00409800                 mov     dword_667A18, ecx       ; store time_limit_1 to memory
.text:00409806                 mov     dword_667A1C, esi        ; store time_limit_2 to memory
.text:0040980C                 jmp     short x50                       ; done


For those not familiar with FPU instructions we like to point to the 64 compile that uses the more common PC flags and states a JBE (jump when less or equal).


And as already pointed out elsewhere 0.0 can not be proven only 0. or .0


That makes already 2 problems on the most hottest discussed instruction. But we are still not there, another problem is that this >= vs > mistake was KNOWN by Rybka investigator Mark Watkins one year before the ICGA investigation started (2010) but was withheld from the evidence and withheld from every forum discussion long after the ICGA verdict.


To complicate matters Richard Vida (programmer of Critter) in September 2013 found a second 0.0 (or .0 or 0.) case that was overlooked by the Rybka investigators and by us as well. It was called gTimeDouble=0.0; by Fadden, a non existing name in Fruit and likely for that reason was overlooked.



 Third error is another sign mistake and again in a part that makes Rybka more Fruitish.


                    FADDEN decomplie                                                  Real Rybka code



    alloc = (time_max + inc * (movestogo - 1)) / 2;
    if (alloc < time_limit_1) alloc = time_limit_1;
    if (alloc > time_max) alloc = time_max;
    time_limit_2 = alloc;

    time_max = time - 5000;    // not in Fruit


    alloc = (inc * (movestogo - 1) + time_max)) / 2;
    if (alloc <= time_limit_1) alloc = time_limit_1;
    if (alloc >= time_max) alloc = time_max;
    time_limit_2 = alloc;



    alloc = (time_max + inc * double(movestogo-1)) * 0.5;
    if (alloc < SearchInput->time_limit_1) alloc = SearchInput->time_limit_1;
    if (alloc > time_max) alloc = time_max;
    SearchInput->time_limit_2 = alloc;




Furthermore we like to stress out the differences between the Fruit and Rybka time control.


  1. The initialization code at the start, Fruit uses -1, Rybka 0.
  2. Fruit while parsing immediately converts to seconds (/1000) (wtime/btime/winc/binc).
  3. Fruit does not subtract 5 seconds from wtime/btime as Rybka does. Why Rybka does this remains a mystery for the moment. There is another odd 5 seconds subtraction in Rybka's movestogo part [ time_max = time - 5000; ] which clearly makes it unique to Fruit's way of handling things.
  4. Fruit has the UCI options Mate, nodes, searchmoves coded. Rybka has no such code.
  5. Fruit reports error messages, Rybka has no such code.
  6. Fruit has:  if (string_equal(ptr,"infinite"))
    While Rybka checks for "is_infinite";
  7. Rybka's special sentinel baptized by Fadden as depthLimit = 0x7FFFFFFF is as also found in the pre-Rybka's (counted 24 of them) but not in Fruit, another sign the time control code is original.
  8. But most important the order of coding is totally different and does not show an obvious trace of code copying.


          1. winc                             binc   (/1000)         
          2. wtime (-5000)               btime (/1000)       
          3. binc                              depth                   
          4. btime (-5000)                infinite
          5. depth                            mate                        not in Rybka
          6. infinite                          movestogo
          7. movestogo                    movetime
          8. movetime                      nodes                       not in Rybka
          9. ponder                          ponder
         10.                                    searchmoves             not in Rybka
         11.                                    winc   (/1000)         
         12.                                    wtime 



If we look at the initialization code of these UCI parameters we get:


RYBKA                   FRUIT

winc         = 0;        binc          = -1.0; 
wtime       = 0;        btime        = -1.0; 
binc          = 0;        movetime  = -1.0;
btime        = 0;        winc         = -1.0;
movetime  = 0;        wtime       = -1.0;

Also not the same order.


Same for the initialization code of the UCI option "movestogo", it is initialized different and also the final calculated timers for search();


RYBKA                     FRUIT

movestogo = 25;       movestogo = -1;
time_limit_1 = -1;      time_limit_1 = 0.0;  (called from a separate subroutine, not in parse_go)

time_limit_2 = -1;      time_limit_2 = 0.0;  (called from a separate subroutine, not in parse_go)


Last differences between Rybka / Fruit in parse_go().


Rybka initializes a number of variables in preparation for calling the search. Fruit has a separate routine for that purpose named clear_search() and (unlike Rybka) it is called from parse_go(), see above comment time_limit_1 & time_limit_2.


From here things get messy due to Fadden's sloppiness to invent non-existing names not present in Fruit and we can only guess its meaning. Richard Vida (programmer of Critter) in September 2013 suggested as follows:


 RYBKA (according Fadden)   FRUIT (according Vida) see search.cpp (line 83) clear_search()
 ignoreClockFlag = 0;  SearchInput->infinite = false;
 depthLimit = 0x7FFFFFFF;  SearchInput->depth_is_limited = false;
 stopSearch = 0;   SearchInfo->stop = false;
 nodeTickLow = 1024;   SearchInfo->check_inc = 10000; // was 100000
 bestMove = 0;   SearchBest->move = MoveNone;
 moveScore = 0;   SearchBest->value = 0;
 depthScore = 0;  SearchRoot->last_value = 0;
 clackFlag  = 0;  SearchInfo->can_stop = false;
 nodeTickHigh = 1;  SearchInfo->check_nb = 10000; // was 100000





BUG 1 - We pitched the 2 rivals Rybka 1.0 beta and Fruit 2.1 at a time control of 1 minute for the whole game and after 32 games Rybka had lost 6 games of time forfeit while Fruit lost none.


As for an educated guess, it feels as if Vasik was trying to fix a bad time control concept creating an extra 5 seconds buffer (the odd 5 second subtractions) that would solve most (but never all) of the time forfeit problems. It does not feel as a copy and paste job at all.


BUG 2 - Furthermore set the time control to "5 seconds fixed time" and notice Rybka 1.0 doesn't move after 5 seconds. Fruit does.  


The Rybka   time_limit_2 = 1000 * movetime;   instruction is definitely wrong.


Copy Fruit and then introduce 2 bugs in 10 lines of code is hardly a valid accusation.



Mark Watkins - The first item to mention is that it already seems not completely natural to place the time management code at the end of the "go" parser as done in both Fruit 2.1 and Rybka 1.0 Beta.


We might agree with Watkins it is quite well possible that Vas borrowed the "start search" idea from Fruit, perhaps the movestogo formula as well but to conclude that the Fruit time control was copied is a couple of bridges too far to our taste, what immediately springs in mind here are not the similarities [ we all use some sort of minimum, average and maximum time variables] but the differences, the frequent losses on time forfeit, this aside of the decompiltaion errors that were made.


Copyright « 2012 Ed Schr÷der