Norman Schmidt, Mon Aug 18, 2008 1:16 pm wrote:FRUIT:
static void parse_setoption( char string [])
{
const char *name;
char* value;
name = strstr(string, "name ");
value = strstr(string, "value ");
if (name == NULL || value == NULL || name >= value)return;
value[-1] = '\0';
name += 5;
value += 6;
STRELKA:
void parse_setoption(char string[])
{
char *name, *value;
int size;
name = strstr(string,"name ");
value = strstr(string,"value ");
if (name == NULL || value == NULL || name >= value) return;
value[-1] = 0;
name += 5;
value += 6;
---------------------------------------------------------------
FRUIT:
bool input_available()
{
static bool init = false, is_pipe;
static HANDLE stdin_h;
DWORD val, error;
if (stdin->_cnt > 0) return true;
if (!init)
{
init = true;
stdin_h = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(stdin_h, &val);
if (!is_pipe)
{
SetConsoleMode(stdin_h, val & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
FlushConsoleInputBuffer(stdin_h);
}
}
if (is_pipe)
{
if (!PeekNamedPipe(stdin_h, NULL, 0, NULL, &val, NULL))
return true;
return val > 0;
}
else
{
GetNumberOfConsoleInputEvents(stdin_h, &val);
return val > 1;
}
return false;
}
STRELKA:
int input_available()
{
static int init = 0, is_pipe;
static HANDLE stdin_h;
DWORD val;
if (stdin->_cnt > 0) return 1;
if (!init)
{
init = 1;
stdin_h = GetStdHandle(STD_INPUT_HANDLE);
is_pipe = !GetConsoleMode(stdin_h, &val);
if (!is_pipe)
{
SetConsoleMode(stdin_h, val & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
FlushConsoleInputBuffer(stdin_h);
}
}
if (is_pipe)
{
if (!PeekNamedPipe(stdin_h, NULL, 0, NULL, &val, NULL))
return 1;
return val > 0;
}
else
{
GetNumberOfConsoleInputEvents(stdin_h, &val);
return val > 1;
}
return 0;
}
---------------------------------------------------------------
FRUIT:
static void parse_position( char string [] )
{
const char *fen;
char* moves;
const char *ptr;
char move_string[256];
int move;
undo_t undo[1];
fen = strstr(string, "fen ");
moves = strstr(string, "moves ");
if (fen != NULL)
{
if (moves != NULL)
{
ASSERT(moves > fen);
moves[-1] = '\0'; // dirty, but so is UCI
}
board_from_fen(SearchInput->board, fen + 4);
}
else
{
board_from_fen(SearchInput->board, StartFen);
}
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
{
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++;
}
}
}
STRELKA:
void parse_position( char string [] )
{
const char *fen;
char *moves;
const char *ptr;
char move_string[256];
int move;
struct undo_t undo[1];
fen = strstr(string, "fen ");
moves = strstr(string, "moves ");
if (fen != NULL)
{
if (moves != NULL)
moves[-1] = 0; // Das ist UCI
board_from_fen(fen + 4);
}
else
board_from_fen(start_pos);
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
{
move_string[4] = *ptr++;
move_string[5] = 0;
}
move = move_from_string(move_string);
move_do(move, undo);
while (*ptr == ' ')
ptr++;
}
}
}
---------------------------------------------------------------
FRUIT:
static void parse_go( char string [] )
{
const char *ptr;
bool infinite, ponder;
int depth, mate, movestogo;
sint64 nodes;
double binc, btime, movetime, winc, wtime;
double time, inc;
double time_max, alloc;
infinite = false;
ponder = false;
depth = -1;
mate = -1;
movestogo = -1;
nodes = -1;
binc = -1.0;
btime = -1.0;
movetime = -1.0;
winc = -1.0;
wtime = -1.0;
ptr = strtok(string, " ");
for ( ptr = strtok(NULL, " "); ptr != NULL; ptr = strtok(NULL, " ") )
{
if (false)
{
}
else if (string_equal(ptr, "binc"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
binc = double(atoi(ptr)) / 1000.0;
ASSERT(binc >= 0.0);
}
else if (string_equal(ptr, "btime"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
btime = double(atoi(ptr)) / 1000.0;
ASSERT(btime >= 0.0);
}
else if (string_equal(ptr, "depth"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
depth = atoi(ptr);
ASSERT(depth >= 0);
}
else if (string_equal(ptr, "infinite"))
{
infinite = true;
}
else if (string_equal(ptr, "mate"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
mate = atoi(ptr);
ASSERT(mate >= 0);
}
else if (string_equal(ptr, "movestogo"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
movestogo = atoi(ptr);
ASSERT(movestogo >= 0);
}
else if (string_equal(ptr, "movetime"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
movetime = double(atoi(ptr)) / 1000.0;
ASSERT(movetime >= 0.0);
}
else if (string_equal(ptr, "nodes"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
nodes = my_atoll(ptr);
ASSERT(nodes >= 0);
}
else if (string_equal(ptr, "ponder"))
{
ponder = true;
}
else if (string_equal(ptr, "searchmoves"))
{
}
else if (string_equal(ptr, "winc"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
winc = double(atoi(ptr)) / 1000.0;
ASSERT(winc >= 0.0);
}
else if (string_equal(ptr, "wtime"))
{
ptr = strtok(NULL, " ");
if (ptr == NULL)
my_fatal("parse_go(): missing argument\n");
wtime = double(atoi(ptr)) / 1000.0;
ASSERT(wtime >= 0.0);
}
}
search_clear();
if (depth >= 0)
{
SearchInput->depth_is_limited = true;
SearchInput->depth_limit = depth;
}
else if (mate >= 0)
{
SearchInput->depth_is_limited = true;
SearchInput->depth_limit = mate * 2 - 1;
}
if (COLOUR_IS_WHITE(SearchInput->board->turn))
{
time = wtime;
inc = winc;
}
else
{
time = btime;
inc = binc;
}
if (movestogo <= 0 || movestogo > 30)
movestogo = 30;
if (inc < 0.0)
inc = 0.0;
if (movetime >= 0.0)
{
SearchInput->time_is_limited = true;
SearchInput->time_limit_1 = movetime * 5.0;
SearchInput->time_limit_2 = movetime;
}
else if (time >= 0.0)
{
time_max = time * 0.95 - 1.0;
if (time_max < 0.0)
time_max = 0.0;
SearchInput->time_is_limited = true;
alloc = (time_max + inc * double(movestogo - 1)) / double(movestogo);
alloc *= (option_get_bool("Ponder") ? PonderRatio : NormalRatio);
if (alloc > time_max)
alloc = time_max;
SearchInput->time_limit_1 = 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;
}
if (infinite || ponder)
SearchInput->infinite = true;
Searching = true;
Infinite = infinite || ponder;
Delay = false;
search();
search_update_current();
Searching = false;
Delay = Infinite;
if (!Delay)
send_best_move();
}
STRELKA:
void start_go( char string [] )
{
const char *ptr;
int infinite, ponder;
int depth, mate, movestogo, zapas;
__int64 nodes;
int binc, btime, movetime, winc, wtime;
int time, inc, alloc;
struct board_t BoardSave[1];
infinite = 0;
ponder = 0;
depth = -1;
mate = -1;
movestogo = -1;
nodes = -1;
binc = -1;
btime = -1;
movetime = -1;
winc = -1;
wtime = -1;
ptr = strtok(string, " ");
for ( ptr = strtok(NULL, " "); ptr != NULL; ptr = strtok(NULL, " ") )
{
if (!strcmp(ptr, "binc"))
{
ptr = strtok(NULL, " ");
binc = atoi(ptr);
}
else if (!strcmp(ptr, "btime"))
{
ptr = strtok(NULL, " ");
btime = atoi(ptr);
}
else if (!strcmp(ptr, "depth"))
{
ptr = strtok(NULL, " ");
depth = atoi(ptr);
}
else if (!strcmp(ptr, "infinite"))
{
infinite = 1;
}
else if (!strcmp(ptr, "mate"))
{
ptr = strtok(NULL, " ");
mate = atoi(ptr);
}
else if (!strcmp(ptr, "movestogo"))
{
ptr = strtok(NULL, " ");
movestogo = atoi(ptr);
}
else if (!strcmp(ptr, "movetime"))
{
ptr = strtok(NULL, " ");
movetime = atoi(ptr);
}
else if (!strcmp(ptr, "nodes"))
{
ptr = strtok(NULL, " ");
sscanf(ptr, "%I64d", &nodes);
}
else if (!strcmp(ptr, "ponder"))
{
ponder = 1;
}
else if (!strcmp(ptr, "winc"))
{
ptr = strtok(NULL, " ");
winc = atoi(ptr);
}
else if (!strcmp(ptr, "wtime"))
{
ptr = strtok(NULL, " ");
wtime = atoi(ptr);
}
}
NS ->(the following 10 lines of code essentially do the same thing as Fruit’s search_clear function, i.e. initialize search vars to 0 or false)
_______________________________________
best_move = 0;
best_score = 0;
depth_score = 0;
check_nb = 1024;
start_time = GetTickCount();
can_stop = 0;
bad_1 = bad_2 = change = easy = flag = 0;
* pv_str = 0;
stop_search = 0;
depth_is_limited = time_is_limited = 0;
________________________________________
if (depth >= 0)
{
depth_is_limited = 1;
depth_limit = depth;
}
else if (mate >= 0)
{
depth_is_limited = 1;
depth_limit = mate * 2 - 1;
}
if ((Board->turn) == 0)
{
time = wtime;
inc = winc;
}
else
{
time = btime;
inc = binc;
}
zapas = 0;
if (movestogo <= 0)
movestogo = 30;
if (movestogo > 30)
{
movestogo = 30;
zapas = 1;
}
time_max = 100000;
if (inc < 0)
inc = 0;
if (movetime >= 0)
{
time_is_limited = 1;
time_max = movetime;
time_limit_1 = movetime * 5;
time_limit_2 = movetime;
}
else if (time >= 0)
{
time_is_limited = 1;
if (zapas)
time_max = ((time / 10) * 9) - 5000;
else
time_max = time - 2000;
if (time_max < 0)
time_max = 0;
alloc = (time_max + inc * (movestogo - 1)) / movestogo;
if (alloc > time_max)
alloc = time_max;
time_limit_1 = alloc;
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;
}
Infinite = 0;
if (infinite || ponder)
Infinite = 1;
Searching = 1;
Delay = 0;
memcpy(BoardSave, Board, sizeof(struct board_t));
start_search();
memcpy(Board, BoardSave, sizeof(struct board_t));
search_time = GetTickCount() - start_time;
if (search_time < 0)
search_time = 0;
Searching = 0;
Delay = Infinite;
if (!Delay)
send_best_move();
}
---------------------------------------------------------------
FRUIT:
void trans_alloc( trans_t *trans )
{
uint32 size, target;
target = option_get_int("Hash");
if (target < 4) target = 16;
target *= 1024 * 1024;
for ( size = 1; size != 0 && size <= target; size *= 2 );
size /= 2;
size /= sizeof(entry_t);
trans->size = size + (ClusterSize - 1);
trans->mask = size - 1;
trans->table = (entry_t *)my_malloc(trans->size * sizeof(entry_t));
trans_clear(trans);
}
STRELKA:
void trans_alloc( int target )
{
int size;
target *= 1024 * 1024;
for ( size = 1; size != 0 && size <= target; size *= 2 );
size /= 2;
size /= sizeof(struct entry_t);
trans_size = size + (ClusterSize - 1);
trans_mask = size - 2;
trans_entry = (struct entry_t *)malloc(trans_size * sizeof(struct entry_t) + 64);
trans_clear();
}
---------------------------------------------------------------
FRUIT:
void trans_store( trans_t *trans, uint64 key, int move, int depth, int min_value, int max_value )
{
entry_t* entry, * best_entry;
int score, best_score;
int i;
trans->write_nb++;
best_entry = NULL;
best_score = -32767;
entry = trans_entry(trans, key);
for ( i = 0; i < ClusterSize; i++, entry++ )
{
if (entry->lock == KEY_LOCK(key))
{
trans->write_hit++;
if (entry->date != trans->date)
trans->used++;
entry->date = trans->date;
if (depth > entry->depth)
entry->depth = depth;
if (move != MoveNone && depth >= entry->move_depth)
{
entry->move_depth = depth;
entry->move = move;
}
if (min_value > -ValueInf && depth >= entry->min_depth)
{
entry->min_depth = depth;
entry->min_value = min_value;
}
if (max_value < +ValueInf && depth >= entry->max_depth)
{
entry->max_depth = depth;
entry->max_value = max_value;
}
return;
}
score = trans->age[entry->date] * 256 - entry->depth;
if (score > best_score)
{
best_entry = entry;
best_score = score;
}
}
entry = best_entry;
if (entry->date == trans->date)
{
trans->write_collision++;
}
else
{
trans->used++;
}
entry->lock = KEY_LOCK(key);
entry->date = trans->date;
entry->depth = depth;
entry->move_depth = (move != MoveNone) ? depth : DepthNone;
entry->move = move;
entry->min_depth = (min_value > -ValueInf) ? depth : DepthNone;
entry->max_depth = (max_value < +ValueInf) ? depth : DepthNone;
entry->min_value = min_value;
entry->max_value = max_value;
}
STRELKA:
void trans_store(unsigned __int16 move, char depth, __int16 value)
{
int i, score, best_score;
struct entry_t *entry;
struct entry_t *best_entry;
best_entry = NULL;
best_score = 0;
entry = trans_entry + (KEY_INDEX &trans_mask);
for ( i = 0; i < ClusterSize; i++, entry++ )
{
if (entry->lock == KEY_LOCK)
{
entry->date = (unsigned char)trans_date;
if (depth > entry->depth)
entry->depth = depth;
if (depth >= entry->move_depth)
{
entry->move_depth = depth;
entry->move = move;
}
if (depth >= entry->min_depth)
{
entry->min_depth = depth;
entry->min_value = value;
}
if (depth >= entry->max_depth)
{
entry->max_depth = depth;
entry->max_value = value;
}
return;
}
score = trans_score[entry->date] - (entry->depth);
if (score > best_score)
{
best_entry = entry;
best_score = score;
}
}
best_entry->lock = KEY_LOCK;
best_entry->date = (unsigned char)trans_date;
best_entry->depth = depth;
best_entry->move_depth = depth;
best_entry->move = move;
best_entry->min_depth = depth;
best_entry->min_value = value;
best_entry->max_depth = depth;
best_entry->max_value = value;
}
---------------------------------------------------------------
FRUIT:
static void loop_step()
{
char string[65536];
get(string, 65536);
if (false)
{
}
else if (string_start_with(string, "debug "))
{
}
else if (string_start_with(string, "go "))
{
if (!Searching && !Delay)
{
init();
parse_go(string);
}
}
else if (string_equal(string, "isready"))
{
if (!Searching && !Delay)
{
init();
}
send("readyok");
}
else if (string_equal(string, "ponderhit"))
{
if (Searching)
{
SearchInput->infinite = false;
Infinite = false;
}
else if (Delay)
{
send_best_move();
Delay = false;
}
}
else if (string_start_with(string, "position "))
{
if (!Searching && !Delay)
{
init();
parse_position(string);
}
}
else if (string_equal(string, "quit"))
{
exit(EXIT_SUCCESS);
}
else if (string_start_with(string, "setoption "))
{
if (!Searching && !Delay)
{
parse_setoption(string);
}
}
else if (string_equal(string, "stop"))
{
if (Searching)
{
SearchInfo->stop = true;
Infinite = false;
}
else if (Delay)
{
send_best_move();
Delay = false;
}
}
else if (string_equal(string, "uci"))
{
send("id name Fruit " VERSION);
send("id author Fabien Letouzey");
option_list();
send("uciok");
}
else if (string_equal(string, "ucinewgame"))
{
if (!Searching && !Delay && Init)
{
trans_clear(Trans);
}
else
{
}
}
}
STRELKA:
void get_uci_command()
{
char string[65536];
char *ptr;
(void)fgets(string, 65536, stdin);
if (feof(stdin))
exit(0);
ptr = strchr(string, '\n');
if (ptr != NULL)
* ptr = 0;
if (!strcmp(string, "uci"))
{
fprintf(stdout, "id name Strelka 2.0 B\n");
fprintf(stdout, "id author Jury Osipov\n");
fprintf(stdout, "option name Hash type spin default 32 min 4 max 1024\n");
fprintf(stdout, "option name MultiPV type spin default 1 min 1 max 100\n");
fprintf(stdout, "uciok\n");
}
else if (!strcmp(string, "ucinewgame"))
{
if (!Searching && !Delay)
trans_clear();
}
else if (!strcmp(string, "isready"))
{
fprintf(stdout, "readyok\n");
}
else if (!strcmp(string, "ponderhit"))
{
if (Searching)
Infinite = 0;
else if (Delay)
{
send_best_move();
Delay = 0;
}
}
else if (!memcmp(string, "position", 8))
{
if (!Searching && !Delay)
parse_position(string);
}
else if (!memcmp(string, "setoption", 9))
{
if (!Searching && !Delay)
parse_setoption(string);
}
else if (!memcmp(string, "go", 2))
{
if (!Searching && !Delay)
start_go(string);
}
else if (!strcmp(string, "stop"))
{
if (Searching)
{
stop_search = 1;
Infinite = 0;
}
else if (Delay)
{
send_best_move();
Delay = 0;
}
}
else if (!strcmp(string, "quit"))
exit(0);
#ifdef TEST_VER
else if (!memcmp(string, "epd", 3))
run_epd_test(string);
else if (!memcmp(string, "pgn", 3))
run_pgn_test(string);
#endif
}
---------------------------------------------------------------
Please note:
both sets of code have been formatted with polystyle for regularity and clarity
ASSERTs have been removed
lines (and blank lines) have been aligned for easy content comparison
all comments removed except for the translation of Fabien's
// dirty, but so is UCI
to
// Das ist UCI
(which is really odd considering Jury is Russian?)
My sincere esitmate is that at least 40-50% of the codebase is extremely similar or exact, with the rest of Strelka's code being a well done bitboard implementation utilizing standard inlined assembly language routines (like first_one, last_one, etc.), various bitmasks, popcnt, etc.
It's clear that a very significant and major effort was required to create this bitboard backend, and integrate it with so much of what appears to be Fruit source code. It's would be no trivial task indeed.
This has nothing to do with it, but from my limited testing (100 games) it appears that Strelka 2.0 is very strong: probably ~+100 ELO better than toga14beta5c, but more games need to be played.
Norm