1 /***************************************************************************
4 begin : Mer Oct 19 2005
5 copyright : (C) 2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 ***************************************************************************/
21 /* each move in the book will be stored in 24 bits */
22 struct PACKED ComprMove
24 unsigned int move
: 14;
25 unsigned int stat
: 10;
28 /* MoveMark and MoveStat are for the book creation */
29 struct PACKED MoveMark
46 MoveMark
& operator[](int i
) {
52 mv_oth
= (MoveMark
*)realloc(mv_oth
, oth_size
*sizeof(MoveMark
));
71 void insert(uint32_t m
, unsigned int w
)
73 for(int i
=0;i
<num
; i
++)
74 if((*this)[i
].move
== m
)
81 (*this)[num
].move
= m
;
82 (*this)[num
].stat
= w
;
87 static int sort_mv_marks(const void *a
, const void *b
)
89 return ((MoveMark
*)b
)->stat
- ((MoveMark
*)a
)->stat
;
94 for(int i
=0;i
<num
-1;i
++)
95 if(mv_oth
[i
].stat
> mv_first
.stat
)
96 SWITCH(mv_oth
[i
], mv_first
);
97 qsort(mv_oth
, num
-1, sizeof(MoveMark
), sort_mv_marks
);
101 typedef std::map
< HashKey
, MoveStat
> BkEntryMap
;
104 /* an entry in the book */
105 struct PACKED BookEntry
108 /* the offset you have to add to find the right branch of the binary tree */
110 /* the number of moves */
115 /* special flags for marking the leaf nodes or those with only 1 child */
116 #define NO_RIGHT ((uint32_t)-1)
117 #define LEAF ((uint32_t)-2)
119 /* the size of the entry in a book with x alternatives */
120 #define ENTRY_SIZE(x) (sizeof(BookEntry) + ((x)-1)*sizeof(ComprMove))
122 static uint32_t calc_book_range_size(BkEntryMap::iterator begin
, BkEntryMap::iterator end
)
125 for(;begin
!=end
;++begin
)
126 sz
+= ENTRY_SIZE(begin
->second
.num
);
130 static int write_book_range(FILE* f
, BkEntryMap::iterator begin
, BkEntryMap::iterator end
)
136 BkEntryMap::iterator mid
= begin
;
144 for(int i
=0;i
<num
/2;i
++)
147 const HashKey
& hk
= mid
->first
;
148 MoveStat
& m
= mid
->second
;
149 uint32_t besz
= ENTRY_SIZE(m
.num
);
150 uint32_t lsize
= calc_book_range_size(begin
, mid
);
151 BkEntryMap::iterator tmpit
= mid
;
156 b
.right_off
= lsize
? NO_RIGHT
: LEAF
;
159 b
.mv
[0].move
= m
[0].move
;
160 b
.mv
[0].stat
= m
[0].stat
;
161 fwrite(&b
, 1, sizeof(BookEntry
), f
);
163 for(int i
=1;i
<m
.num
;i
++)
165 ComprMove c
= { m
[i
].move
, m
[i
].stat
};
166 fwrite(&c
, 1, sizeof(ComprMove
), f
);
170 uint32_t truels
= write_book_range(f
, begin
, mid
);
172 fprintf(stderr
, "Error! %d %d\n", truels
, lsize
);
175 return besz
+ lsize
+ write_book_range(f
, mid
, end
);
178 void Engine::create_book(int argc
, char *argv
[])
182 FILE* f
= fopen(argv
[0],"r");
184 output("Error, could not open \"%s\" for reading.\n", argv
[0]);
189 output("(%d games processed)\n", n
);
191 for(int i
=mv_done_num
-1; i
>=0; i
--)
193 board
.undo_move(mv_done
[i
], save_buf
[--save_buf_num
]);
195 if(i
>v_book_creation_max_depth
)
198 MoveStat
& ms
= b
[board
.hash
];
200 unsigned int weight
= v_book_creation_weigh_draw
;
202 weight
= board
.color_to_move
== BLACK
? v_book_creation_weigh_win
: v_book_creation_weigh_lose
;
203 else if(status
== _10
)
204 weight
= board
.color_to_move
== WHITE
? v_book_creation_weigh_win
: v_book_creation_weigh_lose
;
206 ms
.insert( board
.compress_move(mv_done
[i
]), weight
);
212 /* adjust the entries */
213 output("(preprocessing the tree)\n");
215 for(BkEntryMap::iterator it
= b
.begin(); it
!= b
.end(); )
217 MoveStat
& ms
= it
->second
;
219 /* discard moves played too few times in games */
220 if(ms
.tot
< (unsigned int)v_book_creation_min_games
)
227 /* remove very rare moves) */
228 for(int i
=0;i
<ms
.num
;i
++)
230 if(ms
[i
].stat
*1000 < ms
.tot
*v_book_creation_min_probability
)
232 ms
.tot
-= ms
[i
].stat
;
233 ms
[i
] = ms
[ms
.num
-1];
239 /* renormalize the alternatives up to 1024 */
241 for(int i
=0;i
<ms
.num
;i
++)
244 ms
[i
].stat
= ((prev_tot
+st
)*1024)/ms
.tot
245 - (prev_tot
*1024)/ms
.tot
;
249 /* sort them so the program will give a nicer output :) */
253 FILE *bf
= fopen("ratta.book","w");
254 output("(writing the book)\n");
255 uint32_t sz
= write_book_range(bf
, b
.begin(), b
.end());
256 printf("Book size is %u\n",sz
);
259 st_computer_color
= 0;
262 bool Engine::open_book(const char *f
)
267 book_mmap
= map_file(f
, &book_size
);
270 output("Error, could not open and mmap the book file \"%s\".\n", f
);
275 output("Book file \"%s\" opened and mapped, good!\n", f
);
279 FILE *file
= fopen(f
, "r");
282 output("Error, could not open and mmap the book file \"%s\" (%s).\n", f
, strerror(errno
));
287 fseek(file
, 0, SEEK_END
);
288 book_size
= ftell(file
);
289 fseek(file
, 0, SEEK_SET
);
290 book_mmap
= malloc(book_size
);
291 fread(book_mmap
, book_size
, 1, file
);
294 output("Book file \"%s\" opened and mapped, good!\n", f
);
300 void Engine::close_book()
304 unmap_file(book_mmap
, book_size
);
312 Move
Engine::probe_book(Board
*brd
)
316 if(!book_mmap
|| mv_done_num
>50)
319 /* walk the in-memory mapped binary search tree */
322 BookEntry
*b
= (BookEntry
*)((long)book_mmap
+delta
);
324 /* book entry found */
325 if(b
->key
== brd
->hash
)
327 /* print the (e4 64%, d4 36%)-like thinking line */
330 if(OpeningInfo
* i
= probe_openings(brd
))
331 output("\t0\t0\t0\t0\t%s: %s (", i
->eco
, i
->name
);
333 output("\t0\t0\t0\t0\t(");
335 for(unsigned int i
=0;i
<b
->num
;i
++)
337 Move m
= brd
->uncompress_move(b
->mv
[i
].move
);
338 output("%s%s %.01f%%",
340 brd
->move_to_alg(MoveStr().data(), m
),
341 b
->num
== 1 ? 100 : b
->mv
[i
].stat
*100.0/1024);
347 return brd
->uncompress_move(b
->mv
[0].move
);
350 for(unsigned int i
=0;i
<b
->num
;i
++)
354 return brd
->uncompress_move(b
->mv
[i
].move
);
357 /* this should never happen */
361 if(b
->right_off
== LEAF
)
364 if(brd
->hash
< b
->key
)
367 if(b
->right_off
== 0)
371 delta
+= ENTRY_SIZE(b
->num
);
376 if(b
->right_off
== NO_RIGHT
)
380 delta
+= ENTRY_SIZE(b
->num
) + b
->right_off
;
383 if(delta
< 0 || delta
>= book_size
-16 )
385 output("Error! Damaged binary book!\n");
391 bool Engine::open_lines(const char *linef
)
395 FILE* f
= fopen(linef
,"r");
398 output("Error, could not open \"%s\" for reading.\n", linef
);
404 for(int i
=mv_done_num
-1; i
>=0; i
--)
406 board
.undo_move(mv_done
[i
], save_buf
[--save_buf_num
]);
408 if(mv_done
[i
].val
> 0)
410 std::map
<Move
, int>& ml
= lines
[board
.hash
];
411 ml
[mv_done
[i
]] += mv_done
[i
].val
;
416 output("Lines loaded from file \"%s\", good!\n", linef
);
420 void Engine::close_lines()
425 Move
Engine::probe_lines(Board
*brd
)
427 Lines::iterator it
= lines
.find( brd
->hash
);
428 if( it
== lines
.end() )
432 for(std::map
<Move
, int>::iterator mit
= it
->second
.begin(); mit
!= it
->second
.end(); ++mit
)
438 int r
= rand() % sum
;
439 for(std::map
<Move
, int>::iterator mit
= it
->second
.begin(); mit
!= it
->second
.end(); ++mit
)
440 if( (r
-= mit
->second
) < 0)
446 bool Engine::open_openings(const char *ecos
)
450 FILE* f
= fopen(ecos
,"r");
453 output("Error, could not open \"%s\" for reading.\n", ecos
);
459 while( (argv
= fget_tokenized(f
, ". \t\v\n\r", &argc
)) )
467 board
.set_as_default();
471 /* is this a move number? */
473 strtol(argv
[i
], &e
, 10);
480 Move mv
= board
.move_from_string(argv
[i
]);
484 board
.do_move(mv
, tmp
);
489 if(mv
== Move::None() && i
==argc
-1)
490 openings
[board
.hash
].set(argv
[0], argv
[i
]);
492 printf("Error parsing opening! (%s, %s)\n", argv
[0], argv
[i
]);
501 output("ECO codes loaded from file \"%s\", good!\n", ecos
);
505 void Engine::close_openings()
509 Engine::OpeningInfo
* Engine::probe_openings(Board
*b
)
511 std::map
<HashKey
, OpeningInfo
>::iterator it
= openings
.find(b
->hash
);
512 if(it
== openings
.end())