My Project
obftest.c
Go to the documentation of this file.
1
21#include "search.h"
22#include "options.h"
23#include "const.h"
24#include "settings.h"
25#ifdef LIB_BUILD
26 #include "ui.h"
27#endif
28
29
31typedef struct OBF {
33 int player;
34 struct {
35 int x;
36 int score;
38 int n_moves;
40 char *comments;
42
44enum {
48};
49
54void obf_free(OBF *obf)
55{
56 free(obf->comments);
57 obf->comments = NULL;
58}
59
65static void obf_write(OBF *obf, FILE *f)
66{
67 char s[80];
68 int i;
69
70 if ((obf->board->player | obf->board->opponent) != 0) {
71 board_to_string(obf->board, obf->player, s);
72 fprintf(f, "%s;", s);
73 for (i = 0; i < obf->n_moves; ++i) {
74 putc(' ', f);
75 move_print(obf->move[i].x, 0, f);
76 fprintf(f, ":%+d;", obf->move[i].score);
77 }
78 if (i == 0) fprintf(f, " %+d;", obf->best_score);
79
80 }
81 if (obf->comments) printf(" %% %s", obf->comments);
82 putc('\n', f);
83 fflush(f);
84}
85
92static int obf_read(OBF *obf, FILE *f)
93{
94 char *string, *line, *next;
95 Move move[1];
96 int parse_ok;
97
98 obf->n_moves = 0;
99 obf->best_score = -SCORE_INF;
100 obf->board->player = obf->board->opponent = 0;
101 obf->comments = NULL;
102
103 line = string_read_line(f);
104 if (line) {
105
106 string = parse_skip_spaces(line);
107 if (*string == '%') {
108 obf->comments = string_duplicate(string + 1);
109 parse_ok = OBF_PARSE_SKIP;
110 } else if (*string == '\n' || *string == '\r' || *string == '\0') {
111 parse_ok = OBF_PARSE_SKIP;
112 } else {
113 next = parse_board(string, obf->board, &obf->player);
114 parse_ok = (next > string) ? OBF_PARSE_OK : OBF_PARSE_SKIP;
115 }
116
117 while (parse_ok == OBF_PARSE_OK && *(string = parse_find(next, ';')) == ';') {
118 next = parse_move(++string, obf->board, move);
119 if (next != string) {
120 string = parse_find(next, ':');
121 if (*string == ':') ++string;
122 else {
123 warn("missing score in %s (%d) %s %s\n", line, move->x, next, string);
124 printf("read>"); obf_write(obf, stdout);
125 parse_ok = OBF_PARSE_SKIP;
126 break;
127 }
128 }
129 move->score = -SCORE_INF;
130 next = parse_int(string, &move->score);
131 if (next == string && obf->best_score == -SCORE_INF) {
132 warn("missing best score in %s\n", line);
133 break;
134 }
135
136 if (move->x == NOMOVE && move->score == -SCORE_INF) {
137 break;
138 }
139
140 if (move->score > obf->best_score) obf->best_score = move->score;
141 obf->move[obf->n_moves].x = move->x;
142 obf->move[obf->n_moves].score = move->score;
143 ++obf->n_moves;
144 }
145
146 free(line);
147 return parse_ok;
148 }
149
150 return OBF_PARSE_END;
151}
152
159static void obf_search(Search *search, OBF *obf, int n)
160{
161 int i, j;
162
163 search_cleanup(search);
164 search_set_board(search, obf->board, obf->player);
165 search_set_level(search, options.level, search->n_empties);
166 if (options.depth >= 0) search->options.depth = MIN(options.depth, search->n_empties);
168
170 else search_set_game_time(search, options.time);
171
172 if (options.verbosity >= 2) {
173 printf("\n*** problem # %d ***\n\n", n);
174 board_print(search->board, search->player, stdout);
175 putchar('\n');
176 puts(search->options.header);
177 puts(search->options.separator);
178 } else if (options.verbosity == 1) printf("%3d|", n);
179
180 search_run(search);
181
182 if (options.verbosity) {
183 if (options.verbosity == 1) {
184 result_print(search->result, stdout);
185 }
186 for (i = 0; i < obf->n_moves; ++i) {
187 if (obf->move[i].x == search->result->move) break;
188 }
189 if (obf->best_score != -SCORE_INF) {
190 putchar(' ');
191 if (i < obf->n_moves) {
192 if (obf->move[i].score != obf->best_score) {
193 printf("Erroneous move: ");
194 for (j = 0; j < obf->n_moves; ++j) {
195 if (obf->move[j].score == obf->best_score) {
196 move_print(obf->move[j].x, obf->player, stdout);
197 putchar(' ');
198 }
199 }
200 printf("expected, with score %+d, error = %+d", obf->best_score, obf->best_score - obf->move[i].score);
201 }
202 } else if (obf->best_score != search->result->score) {
203 printf("Erroneous score: %+d expected", obf->best_score);
204 }
205 }
206 putchar('\n');
207 if (options.verbosity >= 2) {
208 puts(search->options.separator);
209 }
210 fflush(stdout);
211 }
212}
213
214
221static void obf_build(Search *search, OBF *obf, int n)
222{
223 int n_moves;
224
225 search_cleanup(search);
226 search_set_board(search, obf->board, obf->player);
227 search_set_level(search, options.level, search->n_empties);
228 if (options.depth >= 0) {
229 search->options.depth = MAX(options.depth, search->n_empties);
230 search->options.selectivity = 0;
231 }
233
235 else search_set_game_time(search, options.time);
236
237
238 if (options.verbosity >= 2) {
239 printf("\n*** problem # %d ***\n\n", n);
240 if (obf->comments) printf("* %s *\n\n", obf->comments);
241 board_print(search->board, search->player, stdout);
242 putchar('\n');
243 puts(search->options.header);
244 puts(search->options.separator);
245 puts(search->options.separator);
246 }
247
248 obf->n_moves = 0;
249 obf->best_score = -SCORE_INF;
250 search->result->score = -SCORE_INF;
251 n_moves = search->movelist->n_moves;
252
253 if (n_moves == 0) {
254 if (options.verbosity == 1) printf("%3d|", n);
255 search_run(search);
256 if (obf->best_score < search->result->score) obf->best_score = search->result->score;
257 if (search->result->move == PASS) {
258 obf->move[obf->n_moves].x = search->result->move;
259 obf->move[obf->n_moves].score = search->result->score;
260 ++obf->n_moves;
261 }
262 }
263
264 while (n_moves--) {
265 if (options.verbosity == 1) printf("%3d|", n);
266
267 search->options.multipv_depth = 60;
268 search_run(search);
270
271 obf->move[obf->n_moves].x = search->result->move;
272 obf->move[obf->n_moves].score = search->result->score;
273 if (obf->best_score < search->result->score) obf->best_score = search->result->score;
274 ++obf->n_moves;
275
276 hash_exclude_move(search->pv_table, search->board, board_get_hash_code(search->board), search->result->move);
277 hash_exclude_move(search->hash_table, search->board, board_get_hash_code(search->board), search->result->move);
278 movelist_exclude(search->movelist, search->result->move);
279 }
280
281 if (options.verbosity) {
282 puts(search->options.separator);
283 if (options.verbosity >= 2) putchar('\n');
284 fflush(stdout);
285 }
286}
287
294void obf_test(Search *search, const char *obf_file, const char *wrong_file)
295{
296 FILE *f, *w = NULL;
297 OBF obf[1];
298 unsigned long long T = 0, n_nodes = 0;
299 int n = 0, n_bad_score = 0, n_bad_move = 0;
300 double score_error = 0.0, move_error = 0.0;
301 int i, ok;
302 bool print_summary = false;
303
304 // add observers
305// search_cleanup(search);
307 search->options.verbosity = (options.verbosity == 1 ? 0 : options.verbosity);
308 options.width -= 4;
309
310 // open script file with problems
311 f = fopen(obf_file, "r");
312 if (f == NULL) {
313 fprintf(stderr, "obf_test: cannot open Othello Position Description's file %s\n", obf_file);
314 exit(EXIT_FAILURE);
315 }
316 if (wrong_file && *wrong_file) {
317 w = fopen(wrong_file, "w");
318 if (w == NULL) {
319 fprintf(stderr, "obf_test: cannot open Othello Position Description's file %s\n", wrong_file);
320 exit(EXIT_FAILURE);
321 }
322 }
323
324 if (options.verbosity == 1) {
325 if (search->options.header) printf(" # |%s\n", search->options.header);
326 if (search->options.separator) printf("---+%s\n", search->options.separator);
327 }
328
329 while ((ok = obf_read(obf, f)) != OBF_PARSE_END) {
330 if (ok == OBF_PARSE_OK) {
331 obf_search(search, obf, ++n);
332
333 T += search_time(search);
334 n_nodes += search_count_nodes(search);
335 for (i = 0; i < obf->n_moves; ++i) {
336 if (obf->move[i].x == search->result->move) break;
337 }
338 if (i < obf->n_moves) {
339 if (obf->move[i].score < obf->best_score) ++n_bad_move;
340 if (obf->move[i].score != search->result->score) ++n_bad_score;
341 move_error += abs(obf->best_score - obf->move[i].score);
342 if (w && obf->move[i].score < obf->best_score) obf_write(obf, w);
343 }
344 if (obf->best_score > -SCORE_INF) score_error += abs(obf->best_score - search->result->score);
345 else print_summary = true;
346 }
347 obf_free(obf);
348 }
349
350 if (options.verbosity == 1 && search->options.separator) puts(search->options.separator);
351 printf("%.30s: ", obf_file);
352 if (n_nodes) printf("%llu nodes in ", n_nodes);
353 time_print(T, false, stdout);
354 if (T > 0 && n_nodes > 0) printf(" (%8.0f nodes/s).", 1000.0 * n_nodes / T);
355 putchar('\n');
356
357 if (print_summary) {
358 printf("%d positions; ", n);
359 printf("%d erroneous move; ", n_bad_move);
360 printf("%d erroneous score; ", n_bad_score);
361 printf("mean absolute score error = %.3f; ", score_error / n);
362 printf("mean absolute move error = %.3f\n", move_error / n);
363 }
364
365 options.width += 4;
366
367 fclose(f);
368 if (w) fclose(w);
369}
370
378void script_to_obf(Search *search, const char *script_file, const char *obf_file)
379{
380
381 FILE *i, *o;
382 OBF obf[1];
383 int n = 0, ok;
384
385 // add observers
388
389 // open script file with problems
390 if (script_file == NULL || obf_file == NULL) {
391 warn("script_to_obf: missing files\n");
392 return;
393 }
394 if (strcmp(script_file, obf_file) == 0) {
395 warn("script_to_obf: files should be different\n");
396 return;
397 }
398
399 i = fopen(script_file, "r");
400 if (i == NULL) {
401 warn("script_to_obf: cannot open script file %s\n", script_file);
402 return;
403 }
404 o = fopen(obf_file, "w");
405 if (o == NULL) {
406 warn("script_to_obf: cannot open obf file %s\n", obf_file);
407 fclose(i);
408 return;
409 }
410
411 if (options.verbosity == 1) {
412 if (search->options.header) printf(" # |%s\n", search->options.header);
413 if (search->options.separator) printf("---+%s\n", search->options.separator);
414 }
415
416 while ((ok = obf_read(obf, i)) != OBF_PARSE_END) {
417 if (ok == OBF_PARSE_OK) {
418 obf_build(search, obf, ++n);
419 }
420 obf_write(obf, o);
421 obf_free(obf);
422 }
423
424 if (options.verbosity == 1 && search->options.separator) puts(search->options.separator);
425 putchar('\n');
426
427 fclose(o);
428 fclose(i);
429
430}
431
437void obf_filter(const char *input_file, const char *output_file)
438{
439 FILE *in, *out;
440 int i, n, f, ok;
441 int n_best, second_best;
442 OBF obf[1];
443
444 // open script file with problems
445 in = fopen(input_file, "r");
446 if (in == NULL) {
447 fprintf(stderr, "obf_filter: cannot open Othello Position Description's file %s\n", input_file);
448 exit(EXIT_FAILURE);
449 }
450 out = fopen(output_file, "w");
451 if (out == NULL) {
452 fprintf(stderr, "obf_filter: cannot open Othello Position Description's file %s\n", output_file);
453 exit(EXIT_FAILURE);
454 }
455
456 n = f = 0;
457 while ((ok = obf_read(obf, in)) != OBF_PARSE_END) {
458 if (ok == OBF_PARSE_OK) {
459 ++n;
460 n_best = 0;
461 second_best = obf->best_score - 4;
462 for (i = 0; i < obf->n_moves; ++i) {
463 if (obf->move[i].score == obf->best_score) ++n_best;
464 else if (obf->move[i].score > second_best) second_best = obf->move[i].score;
465 }
466 if (n_best == 1 && second_best == obf->best_score - 2) {
467 ++f;
468 obf_write(obf, out);
469 }
470 }
471 obf_free(obf);
472 }
473
474 printf("OBF filter: %d selected out of %d positions\n", f, n);
475
476 fclose(in);
477 fclose(out);
478}
479
484void _obf_speed(Search *search, const int n, BenchResult *result)
485{
486 int i;
487 unsigned long long t = real_clock();
488 unsigned long long T = 0, n_nodes = 0;
489 const int level = options.level;
490 Random r[1];
491 OBF obf;
492
493 obf.n_moves = 0;
494 obf.best_score = -SCORE_INF;
495
496 random_seed(r, 42);
497 options.level = 60;
499 search->options.verbosity = (options.verbosity == 1 ? 0 : options.verbosity);
500 options.width -= 4;
501
502 if (options.verbosity == 1) {
503 if (search->options.header) printf(" # |%s\n", search->options.header);
504 if (search->options.separator) printf("---+%s\n", search->options.separator);
505 }
506
507 for (i = 0; n == - 1 ? real_clock() - t < 60000 : i < n; ++i) {
508 const int ply = MAX(30, 40 - i / 5);
509 obf.player = ply & 1;
510 board_rand(obf.board, ply, r);
511 obf_search(search, &obf, i + 1);
512 T += search_time(search);
513 n_nodes += search_count_nodes(search);
514#ifdef LIB_BUILD
515 if ( result != NULL ) {
516 lock(result);
517 result->T = T;
518 result->n_nodes = n_nodes;
519 result->positions = i + 1;
520 unlock(result);
521 }
522#endif
523 }
524 printf("%d positions solved: ", i);
525 if (n_nodes) printf("%llu nodes in ", n_nodes);
526 time_print(T, false, stdout);
527 if (T > 0 && n_nodes > 0) printf(" (%8.0f nodes/s).", 1000.0 * n_nodes / T);
528 putchar('\n');
529
530 options.level = level;
531 options.width += 4;
532
533}
534void obf_speed(Search *search, const int n)
535{
536 _obf_speed(search, n, NULL);
537}
unsigned long long board_get_hash_code(const Board *board)
Compute a hash code.
Definition board.c:1134
void board_print(const Board *board, const int player, FILE *f)
Print out the board.
Definition board.c:1230
char * board_to_string(const Board *board, const int player, char *s)
convert the to a compact string.
Definition board.c:1272
void board_rand(Board *board, int n_ply, Random *r)
Get a random board by playing random moves.
Definition board.c:406
#define SCORE_INF
Definition const.h:52
@ PASS
Definition const.h:37
@ NOMOVE
Definition const.h:37
#define MAX_MOVE
Definition const.h:18
void hash_exclude_move(HashTable *hash_table, const unsigned long long hash_code, const int move)
Erase an hash table entry.
Definition hash-lock-free.c:629
void move_print(const int x, const int player, FILE *f)
Print out a move.
Definition move.c:110
Move * movelist_exclude(MoveList *movelist, const int move)
Exclude a move.
Definition move.c:516
void obf_speed(Search *search, const int n)
Definition obftest.c:534
static void obf_write(OBF *obf, FILE *f)
Write an OBF structure.
Definition obftest.c:65
void obf_free(OBF *obf)
Free an OBF structure.
Definition obftest.c:54
static void obf_build(Search *search, OBF *obf, int n)
Build an OBF structure.
Definition obftest.c:221
void obf_filter(const char *input_file, const char *output_file)
Select hard position from an OBF file.
Definition obftest.c:437
static void obf_search(Search *search, OBF *obf, int n)
Analyze an OBF structure.
Definition obftest.c:159
struct OBF OBF
static int obf_read(OBF *obf, FILE *f)
Read an OBF structure.
Definition obftest.c:92
void script_to_obf(Search *search, const char *script_file, const char *obf_file)
Build an OBF file from a Script file.
Definition obftest.c:378
void _obf_speed(Search *search, const int n, BenchResult *result)
Test edax speed by running for at least 1 minutes on problems deeper and deeper.
Definition obftest.c:484
void obf_test(Search *search, const char *obf_file, const char *wrong_file)
Test an OBF file.
Definition obftest.c:294
@ OBF_PARSE_END
Definition obftest.c:47
@ OBF_PARSE_SKIP
Definition obftest.c:46
@ OBF_PARSE_OK
Definition obftest.c:45
Options options
Definition options.c:22
@ EDAX_TIME_PER_MOVE
Definition options.h:20
void * search_run(void *v)
Search the bestmove of a given board.
Definition root.c:810
void search_set_level(Search *search, const int level, const int n_empties)
Set the search level.
Definition search.c:609
unsigned long long search_count_nodes(Search *search)
Return the number of nodes searched.
Definition search.c:1073
void result_print(Result *result, FILE *f)
Print the current search result.
Definition search.c:1106
void search_cleanup(Search *search)
Clean-up some search data.
Definition search.c:578
void search_set_observer(Search *search, void(*observer)(Result *))
set observer.
Definition search.c:1095
void search_set_board(Search *search, const Board *board, const int player)
Set the board to analyze.
Definition search.c:593
void search_set_move_time(Search *search, const long long t)
set time to search.
Definition search.c:686
void search_observer(Result *result)
default observer.
Definition search.c:1083
long long search_time(Search *search)
Return the time spent by the search.
Definition search.c:1061
void search_set_game_time(Search *search, const long long t)
set time to search.
Definition search.c:671
#define MULTIPV_DEPTH
Definition settings.h:122
Definition ui.h:48
unsigned long long T
Definition ui.h:49
int positions
Definition ui.h:51
unsigned long long n_nodes
Definition ui.h:50
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
int n_moves
Definition move.h:31
Definition move.h:20
int score
Definition move.h:23
int x
Definition move.h:22
Definition obftest.c:31
char * comments
Definition obftest.c:40
int score
Definition obftest.c:36
int best_score
Definition obftest.c:39
struct OBF::@20 move[MAX_MOVE]
int x
Definition obftest.c:35
int player
Definition obftest.c:33
Board board[1]
Definition obftest.c:32
int n_moves
Definition obftest.c:38
PlayType play_type
Definition options.h:42
int level
Definition options.h:40
int depth
Definition options.h:44
int width
Definition options.h:34
long long time
Definition options.h:41
int selectivity
Definition options.h:45
int verbosity
Definition options.h:32
Definition util.h:87
int move
Definition search.h:44
int score
Definition search.h:45
Definition search.h:95
const char * separator
Definition search.h:145
int n_empties
Definition search.h:99
MoveList movelist[1]
Definition search.h:132
Result * result
Definition search.h:151
const char * header
Definition search.h:144
int player
Definition search.h:100
struct Search::@25 options
int verbosity
Definition search.h:142
int depth
Definition search.h:117
HashTable pv_table[1]
Definition search.h:104
HashTable hash_table[1]
Definition search.h:103
int selectivity
Definition search.h:118
Board board[1]
Definition search.h:96
int multipv_depth
Definition search.h:147
User interface header.
void time_print(long long t, bool justified, FILE *f)
Print time as "D:HH:MM:SS.CC".
Definition util.c:131
char * parse_move(const char *string, const Board *board, Move *move)
Parse a move.
Definition util.c:627
char * string_duplicate(const char *s)
Duplicate a string.
Definition util.c:299
char * parse_int(const char *string, int *result)
Parse an integer.
Definition util.c:761
char * string_read_line(FILE *f)
Read a line.
Definition util.c:265
char * parse_skip_spaces(const char *string)
Skip spaces.
Definition util.c:514
void random_seed(Random *random, const unsigned long long seed)
Pseudo-random number seed.
Definition util.c:1062
char * parse_find(const char *string, const int c)
Find a char.
Definition util.c:545
char * parse_board(const char *string, Board *board, int *player)
Parse a board.
Definition util.c:682
long long real_clock(void)
#define MIN(a, b)
Definition util.h:101
#define warn(...)
Display a warning message as "WARNING : ... ".
Definition util.h:373
#define MAX(a, b)
Definition util.h:98