13
#include "book_make.h"
16
#include "move_legal.h"
23
static const int COUNT_MAX = 16384;
25
static const int NIL = -1;
51
static book_t Book[1];
55
static void book_clear ();
56
static void book_insert (const char file_name[]);
57
static void book_score ();
58
static void book_filter ();
59
static void book_sort ();
60
static void book_save (const char file_name[]);
62
static int find_entry (const board_t * board, int move);
63
static void resize ();
64
static void halve_stats (uint64 key);
66
static bool keep_entry (int pos);
68
static int move_score (const entry_t * entry);
70
static int key_compare (const void * p1, const void * p2);
72
static void write_integer (FILE * file, int size, uint64 n);
78
void book_make(int argc, char * argv[]) {
81
const char * pgn_file;
82
const char * bin_file;
85
my_string_set(&pgn_file,"book.pgn");
88
my_string_set(&bin_file,"book.bin");
94
for (i = 1; i < argc; i++) {
98
} else if (my_string_equal(argv[i],"make-book")) {
102
} else if (my_string_equal(argv[i],"-pgn")) {
105
if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
107
my_string_set(&pgn_file,argv[i]);
109
} else if (my_string_equal(argv[i],"-bin")) {
112
if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
114
my_string_set(&bin_file,argv[i]);
116
} else if (my_string_equal(argv[i],"-max-ply")) {
119
if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
121
MaxPly = atoi(argv[i]);
123
} else if (my_string_equal(argv[i],"-min-game")) {
126
if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
128
MinGame = atoi(argv[i]);
130
} else if (my_string_equal(argv[i],"-min-score")) {
133
if (argv[i] == NULL) my_fatal("book_make(): missing argument\n");
135
MinScore = atoi(argv[i]);
139
my_fatal("book_make(): unknown option \"%s\"\n",argv[i]);
145
printf("inserting games ...\n");
146
book_insert(pgn_file);
148
printf("scoring entries ...\n");
151
printf("filtering entries ...\n");
154
printf("sorting entries ...\n");
157
printf("saving entries ...\n");
160
printf("all done!\n");
165
static void book_clear() {
170
Book->mask = (Book->alloc * 2) - 1;
172
Book->entry = (entry_t *) my_malloc(Book->alloc*sizeof(entry_t));
175
Book->hash = (sint32 *) my_malloc((Book->alloc*2)*sizeof(sint32));
176
for (index = 0; index < Book->alloc*2; index++) {
177
Book->hash[index] = NIL;
183
static void book_insert(const char file_name[]) {
194
ASSERT(file_name!=NULL);
202
pgn_open(pgn,file_name);
204
while (pgn_next_game(pgn)) {
211
} else if (my_string_equal(pgn->result,"1-0")) {
213
} else if (my_string_equal(pgn->result,"0-1")) {
217
while (pgn_next_move(pgn,string,256)) {
221
move = move_from_san(string,board);
223
if (move == MoveNone || !move_is_legal(move,board)) {
224
my_fatal("book_insert(): illegal move \"%s\" at line %d, column %d\n",string,pgn->move_line,pgn->move_column);
227
pos = find_entry(board,move);
229
Book->entry[pos].n++;
230
Book->entry[pos].sum += result+1;
232
if (Book->entry[pos].n >= COUNT_MAX) {
233
halve_stats(board->key);
243
if (game_nb % 10000 == 0) printf("%d games ...\n",game_nb);
248
printf("%d game%s.\n",game_nb,(game_nb>1)?"s":"");
249
printf("%d entries.\n",Book->size);
256
static void book_score() {
263
for (pos = 0; pos < Book->size; pos++) {
265
ASSERT(Book->entry[pos].n<65536);
267
score = move_score(&Book->entry[pos]);
269
ASSERT(score>=0&&score<65536);
270
Book->entry[pos].score = score;
276
static void book_filter() {
284
for (src = 0; src < Book->size; src++) {
285
if (keep_entry(src)) Book->entry[dst++] = Book->entry[src];
288
ASSERT(dst>=0&&dst<=Book->size);
291
printf("%d entries.\n",Book->size);
296
static void book_sort() {
298
// sort keys for binary search
300
qsort(Book->entry,Book->size,sizeof(entry_t),&key_compare);
305
static void book_save(const char file_name[]) {
310
ASSERT(file_name!=NULL);
312
file = fopen(file_name,"wb");
313
if (file == NULL) my_fatal("book_save(): can't open file \"%s\" for writing: %s\n",file_name,strerror(errno));
317
for (pos = 0; pos < Book->size; pos++) {
319
ASSERT(keep_entry(pos));
320
ASSERT(Book->entry[pos].score<65536);
322
write_integer(file,8,Book->entry[pos].key);
323
write_integer(file,2,Book->entry[pos].move);
324
write_integer(file,2,Book->entry[pos].score);
325
write_integer(file,2,0);
326
write_integer(file,2,0);
334
static int find_entry(const board_t * board, int move) {
341
ASSERT(move_is_ok(move));
343
ASSERT(move_is_legal(move,board));
351
for (index = key & Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {
353
ASSERT(pos>=0&&pos<Book->size);
355
if (Book->entry[pos].key == key && Book->entry[pos].move == move) {
362
ASSERT(Book->size<=Book->alloc);
364
if (Book->size == Book->alloc) {
366
// allocate more memory
370
for (index = key & Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)
374
// create a new entry
376
ASSERT(Book->size<Book->alloc);
379
Book->entry[pos].key = key;
380
Book->entry[pos].move = move;
381
Book->entry[pos].n = 0;
382
Book->entry[pos].sum = 0;
383
Book->entry[pos].score = 0;
385
// insert into the hash table
387
ASSERT(index>=0&&index<Book->alloc*2);
388
ASSERT(Book->hash[index]==NIL);
389
Book->hash[index] = pos;
391
ASSERT(pos>=0&&pos<Book->size);
398
static void resize() {
404
ASSERT(Book->size==Book->alloc);
407
Book->mask = (Book->alloc * 2) - 1;
410
size += Book->alloc * sizeof(entry_t);
411
size += (Book->alloc*2) * sizeof(sint32);
413
if (size >= 1048576) printf("allocating %gMB ...\n",double(size)/1048576.0);
417
Book->entry = (entry_t *) my_realloc(Book->entry,Book->alloc*sizeof(entry_t));
418
Book->hash = (sint32 *) my_realloc(Book->hash,(Book->alloc*2)*sizeof(sint32));
420
// rebuild hash table
422
for (index = 0; index < Book->alloc*2; index++) {
423
Book->hash[index] = NIL;
426
for (pos = 0; pos < Book->size; pos++) {
428
for (index = Book->entry[pos].key & Book->mask; Book->hash[index] != NIL; index = (index+1) & Book->mask)
431
ASSERT(index>=0&&index<Book->alloc*2);
432
Book->hash[index] = pos;
438
static void halve_stats(uint64 key) {
445
for (index = key & Book->mask; (pos=Book->hash[index]) != NIL; index = (index+1) & Book->mask) {
447
ASSERT(pos>=0&&pos<Book->size);
449
if (Book->entry[pos].key == key) {
450
Book->entry[pos].n = (Book->entry[pos].n + 1) / 2;
451
Book->entry[pos].sum = (Book->entry[pos].sum + 1) / 2;
458
static bool keep_entry(int pos) {
460
ASSERT(pos>=0&&pos<Book->size);
462
// return move_score(&Book->entry[pos]) > 0;
464
return Book->entry[pos].score > 0;
469
static int move_score(const entry_t * entry) {
477
if (entry->n >= MinGame) {
478
// score = entry->n; // popularity
479
score = entry->sum; // "expectancy"
489
static int key_compare(const void * p1, const void * p2) {
491
const entry_t * entry_1, * entry_2;
496
entry_1 = (const entry_t *) p1;
497
entry_2 = (const entry_t *) p2;
499
if (entry_1->key > entry_2->key) {
501
} else if (entry_1->key < entry_2->key) {
504
return entry_2->score - entry_1->score; // highest score first
510
static void write_integer(FILE * file, int size, uint64 n) {
516
ASSERT(size>0&&size<=8);
517
ASSERT(size==8||n>>(size*8)==0);
519
for (i = size-1; i >= 0; i--) {
520
b = (n >> (i*8)) & 0xFF;
526
// end of book_make.cpp