My Project
cassio.c
Go to the documentation of this file.
1
21#include "cassio.h"
22
23#include "event.h"
24#include "options.h"
25#include "search.h"
26#include "settings.h"
27#include "ybwc.h"
28#include "stats.h"
29#include "util.h"
30#include <assert.h>
31
32#include <stdarg.h>
33#include <math.h>
34
36
37#define ENGINE_N_POSITION 1024
38
40static char engine_result[1024];
42static char last_line_sent[1024];
43
54
55
61static void engine_send(const char *format, ...)
62{
63 va_list args;
64
65 va_start(args, format);
66 vprintf(format, args);
67 va_end(args);
68 putchar('\n'); fflush(stdout);
69
72 fprintf(engine_log->f, "sent> \"");
73 va_start(args, format);
74 vfprintf(engine_log->f, format, args);
75 va_end(args);
76 fprintf(engine_log->f, "\"\n");
77 fflush(engine_log->f);
78 }
79}
80
86static void engine_get_input(Engine *engine)
87{
88 char protocol[32], cmd[32];
89 Event *event = engine->event;
90 char *buffer_with_garbage;
91 char *buffer = NULL;
92
93 buffer_with_garbage = string_read_line(stdin);
96 fprintf(engine_log->f, "received< \"%s\"\n", buffer_with_garbage);
97 }
98
99 if (buffer_with_garbage == NULL) { // stdin closed or not working
100 buffer_with_garbage = string_duplicate("ENGINE-PROTOCOL eof");
101 event->loop = false;
102 }
103
104 buffer = parse_word(buffer_with_garbage, protocol, 32);
105
106 if (strcmp(protocol, "ENGINE-PROTOCOL") == 0) {
107 buffer = string_duplicate(buffer);
108 parse_word(buffer, cmd, 32);
110 // stop or quit: Interrupt immediately the current search & remove unprocessed messages.
111 if (strcmp(cmd, "stop") == 0) {
113 if (engine->is_searching) {
114 engine_stop(engine->search);
115 } else {
116 engine_send("ready.");
117 }
118 } else if (strcmp(cmd, "get-search-infos") == 0) {
119 if (engine->is_searching) {
120 engine_send("node %lld, time %.3f", search_count_nodes(engine->search), 0.001 * search_time(engine->search));
121 } else {
122 engine_send("ready.");
123 }
124 } else {
125 if (strcmp(cmd, "quit") == 0) {
126 engine_stop(engine->search);
128 event->loop = false;
129 }
130 // add the message (including quit) to a queue for later processing.
131 event_add_message(event, buffer);
132 lock(event);
133 condition_signal(event);
134 unlock(event);
135
136 }
137 } else if (*protocol == '\0') {
138 if (engine->is_searching) {
139 engine_send("ok.");
140 } else {
141 engine_send("ready.");
142 }
143 } else {
144 engine_send("ERROR: Unknown protocol \"%s\"", buffer_with_garbage);
145 }
146
147 free(buffer_with_garbage);
148}
149
157static void engine_wait_input(Engine *engine, char **cmd, char **param)
158{
159 event_wait(engine->event, cmd, param);
160}
161
167static void* engine_input_loop(void *v)
168{
169 Engine *engine = (Engine*) v;
170
171
172 while (engine->event->loop && !feof(stdin) && !ferror(stdin)) {
173 engine_get_input(engine);
174 }
175
176 engine->event->loop = false;
177 cassio_debug("Quit input loop\n");
178
179 return NULL;
180}
181
186static bool is_position_new(Engine *engine, Board *board)
187{
188 int i;
189
190 for (i = 0; i < engine->last_position.n; ++i) {
191 if (board_equal(board, engine->last_position.board + i)) return false;
192 }
193
194 if (i == ENGINE_N_POSITION) {
195 cassio_debug("Position list: removing position %llx\n", board_get_hash_code(board));
196 }
197 while (--i > 0) {
198 engine->last_position.board[i] = engine->last_position.board[i - 1];
199 }
200 cassio_debug("Position list: adding position %llx\n", board_get_hash_code(board));
201 engine->last_position.board[0] = *board;
202 engine->last_position.n = MIN(ENGINE_N_POSITION, engine->last_position.n + 1);
203 hash_clear(engine->search->hash_table);
204 hash_clear(engine->search->pv_table);
206
207 return true;
208}
209
214static void engine_observer(Result *result)
215{
216 int n = 72;
217 char color = (engine_result[64] == 'O' ? 'W' : 'B');
218
219 move_to_string(result->move, color == 'W' ? WHITE : BLACK, engine_result + n); n += 2;
220 n += sprintf(engine_result + n, ", depth %d, @%d%%, %c%+d.00 <= v <= %c%+d.00, ",
221 result->depth, selectivity_table[result->selectivity].percent,
222 color, result->bound[result->move].lower, color, result->bound[result->move].upper);
223 line_to_string(result->pv, result->pv->n_moves, NULL, engine_result + n);
224 n += 2 * result->pv->n_moves;
225 n += sprintf(engine_result + n, ", node %llu, time %.3f", result->n_nodes, 0.001 * result->time);
226
227 // avoid to send multiple times the same result.
228 if (strncmp(engine_result + 72, last_line_sent, n - 75) != 0) {
229 strcpy(last_line_sent, engine_result + 72);
231 }
232}
233
239{
240 Search *search;
241
242 search = (Search*) malloc(sizeof (Search));
243 if (search == NULL) {
244 engine_send("ERROR: Cannot allocate a new search engine.");
245 engine_send("bye bye!");
246 exit(EXIT_FAILURE);
247 }
248
249 search_init(search);
251
252 return search;
253}
254
268static int engine_open(Search *search, const Board *board, const int player, const int alpha, const int beta, const int depth, const int precision)
269{
270 int k;
271 HashData hash_data[1];
272 Move *move;
273 int score = 0;
274
275 search->time.spent = -time_clock();
276 search->stop = RUNNING;
277
278 // set alphabeta bounds
279 options.alpha = alpha;
281
282 options.beta = beta;
283 BOUND(options.beta, options.alpha + 1, SCORE_MAX, "beta");
284
285 // other initializations
286 search->n_nodes = 0;
287 search->child_nodes = 0;
288 search_time_init(search);
289 if (!search->options.keep_date) {
290 hash_clear(search->hash_table);
291 hash_clear(search->pv_table);
292 hash_clear(search->shallow_table);
293 }
294
295 search->height = 0;
296 search->node_type[search->height] = PV_NODE;
297 search->result->score = 0;
298 search->stability_bound.upper = SCORE_MAX - 2 * get_stability(board->opponent, board->player);
299 search->stability_bound.lower = 2 * get_stability(board->player, board->opponent) - SCORE_MAX;
300
301 // set the board
302 if (player != search->player || !board_equal(search->board, board)) {
303 search_set_board(search, board, player);
304
305 if (hash_get(search->pv_table, board, board_get_hash_code(board), hash_data)) {
306 if (hash_data->lower == -SCORE_INF && hash_data->upper < SCORE_INF) score = hash_data->upper;
307 else if (hash_data->upper == +SCORE_INF && hash_data->lower > -SCORE_INF) score = hash_data->lower;
308 else score = (hash_data->upper + hash_data->lower) / 2;
309 }
310 if (!movelist_is_empty(search->movelist)) {
311 movelist_evaluate(search->movelist, search, hash_data, options.alpha, depth);
312 movelist_sort(search->movelist);
313 }
314 }
315
316 foreach_move(move, search->movelist) {
317 search->result->bound[move->x].lower = SCORE_MIN;
318 search->result->bound[move->x].upper = SCORE_MAX;
319 }
320
321 search->result->n_moves_left = search->result->n_moves = search->movelist->n_moves;
322 search->result->book_move = false;
323
324 // set level
325 search->depth = depth;
326 if (options.transgress_cassio && (search->n_empties & 1) != (depth & 1)) ++search->depth;
327 if (options.transgress_cassio && search->depth > search->n_empties - 10) search->depth = search->n_empties;
328 search->options.depth = search->depth;
329
330 BOUND(search->depth, 0, search->n_empties, "depth");
331 search->depth_pv_extension = get_pv_extension(search->depth, search->n_empties);
332
333 if (options.transgress_cassio && depth < search->n_empties) k = 0;
334 else if (precision <= 73) k = 0;
335 else if (precision <= 87) k = 1;
336 else if (precision <= 95) k = 2;
337 else if (precision <= 98) k = 3;
338 else if (precision <= 99) k = 4;
339 else k = 5;
340 search->options.selectivity = search->selectivity = k;
341
342 *last_line_sent = '\0';
343 board_to_string(board, player, engine_result);
345 strcpy(engine_result + 65, ", move ");
346
347 return score;
348}
349
355static void engine_close(Search *search)
356{
357 search->result->n_nodes = search_count_nodes(search);
358 search->time.spent += time_clock();
359 search->result->time = search->time.spent;
360
361 statistics_sum_nodes(search);
362
363 // in case nothing have been sent yet...
364 if (*last_line_sent == '\0' && search->stop == RUNNING) engine_observer(search->result);
365
366 search->stop = STOP_END;
367}
368
376void* engine_init(void)
377{
378 Engine *engine;
379
381
382 engine = (Engine*) malloc(sizeof (Engine));
383 if (engine == NULL) {
384 engine_send("ERROR: Cannot allocate a new engine.");
385 engine_send("bye bye!");
386 exit(EXIT_FAILURE);
387 }
388 engine->is_searching = false;
389 engine->search = engine_create_search();
390 event_init(engine->event);
391
392 thread_create2(&engine->event->thread, engine_input_loop, engine); // modified for iOS by lavox. 2018/1/16
393 thread_detach(engine->event->thread);
394
395 return engine;
396}
397
402void engine_free(void *v)
403{
404 Search *search = (Search*) v;
405 if (search) {
406 search_free(search);
407 free(search);
408 }
410}
411
412
413
414void feed_all_hash_table(Search *search, Board *board, const int depth, const int selectivity, const int lower, const int upper, const int move)
415{
416 const unsigned long long hash_code = board_get_hash_code(board);
417
418 hash_feed(search->hash_table, board, hash_code, depth, selectivity, lower, upper, move);
419 hash_feed(search->pv_table, board, hash_code, depth, selectivity, lower, upper, move);
420}
421
433void engine_feed_hash(void *v, Board *board, int lower, int upper, const int depth, const int precision, Line *pv)
434{
435 Engine *engine = (Engine*) v;
436 Search *search = engine->search;
437 int i, selectivity, tmp;
438 int current_depth;
439 Move *move, *child_move;
440 MoveList movelist[1], child_movelist[1];
441
442 if (options.transgress_cassio && depth < board_count_empties(board)) selectivity = 0;
443 else if (precision <= 73) selectivity = 0;
444 else if (precision <= 87) selectivity = 1;
445 else if (precision <= 95) selectivity = 2;
446 else if (precision <= 98) selectivity = 3;
447 else if (precision <= 99) selectivity = 4;
448 else selectivity = 5;
449
450 pv->move[pv->n_moves] = NOMOVE;
451
452 for (i = 0; i <= pv->n_moves; ++i) {
453 current_depth = depth - i;
454 feed_all_hash_table(search, board, current_depth, selectivity, lower, upper, pv->move[i]);
455
456 movelist_get_moves(movelist, board);
457 movelist_sort_bestmove(movelist, pv->move[i]);
458
459 foreach_move(move, movelist) {
460 board_update(board, move);
461 if (move->x == pv->move[i]) {
462 feed_all_hash_table(search, board, current_depth - 1, selectivity, -upper, -lower, NOMOVE);
463 if (lower > SCORE_MIN) {
464 movelist_get_moves(child_movelist, board);
465 foreach_move(child_move, child_movelist) {
466 board_update(board, child_move);
467 feed_all_hash_table(search, board, current_depth - 2, selectivity, lower, SCORE_MAX, NOMOVE);
468 board_restore(board, child_move);
469 }
470 }
471 } else if (upper < SCORE_MAX) {
472 feed_all_hash_table(search, board, current_depth - 1, selectivity, -upper, SCORE_MAX, NOMOVE);
473 }
474 board_restore(board, move);
475 }
476
477 move = movelist_first(movelist);
478
479 if (move && move->x == pv->move[i]) {
480 board_update(board, move);
481 tmp = lower;
482 lower = -upper;
483 upper = -tmp;
484 } else if (!move && pv->move[i] == PASS && board_is_pass(board)) {
485 board_pass(board);
486 tmp = lower;
487 lower = -upper;
488 upper = -tmp;
489 } else {
490 break;
491 }
492 }
493}
494
495
501void engine_empty_hash(void *v)
502{
503 Engine *engine = (Engine*) v;
504
505 if (engine && engine->search && engine->search->hash_table && engine->search->pv_table) {
506 cassio_debug("clear the hash-table.\n");
507 engine->last_position.n = 0;
509 hash_cleanup(engine->search->pv_table);
511 }
512}
513
520static bool skip_search(Engine *engine, int *old_score)
521{
522 Search *search = engine->search;
523 Board *board = search->board;
524 MoveList *movelist = search->movelist;
525 HashData hash_data[1];
526 Move *bestmove;
527 int alpha = options.alpha;
528 int beta = options.beta;
529 Bound *bound;
530 char s[4], b[80];
531 const unsigned long long hash_code = board_get_hash_code(board);
532
533 *old_score = 0;
534
535 if (hash_get(search->pv_table, board, hash_code, hash_data)
536 || hash_get(search->hash_table, board, hash_code, hash_data)) {
537 // compute bounds
538 if (alpha < hash_data->lower) alpha = *old_score = hash_data->lower;
539 if (beta > hash_data->upper) beta = *old_score = hash_data->upper;
540 // skip search ?
541 if (hash_data->depth >= search->depth && hash_data->selectivity >= search->selectivity && alpha >= beta) {
542 if (hash_data->move[0] != NOMOVE) movelist_sort_bestmove(movelist, hash_data->move[0]);
543 else if (hash_data->lower > SCORE_MIN) return false;
544 bestmove = movelist_first(movelist);
545 bestmove->score = *old_score;
546 record_best_move(search, board, bestmove, options.alpha, options.beta, search->depth);
547 bound = search->result->bound + bestmove->x;
548
549 if (bound->lower != bound->upper || is_pv_ok(search, bestmove->x, search->depth)) {
550 cassio_debug("Edax skips the search. The position is already in the hash table: %s (%d, %d) ?\n", move_to_string(bestmove->x, search->player, s), hash_data->lower, hash_data->upper);
551 engine_observer(search->result);
552 return true;
553 } else {
554 cassio_debug("Edax does not skip the search : BAD PV!\n");
555 }
556 } else {
557 if (hash_data->depth < search->depth || hash_data->selectivity < search->selectivity) {
558 cassio_debug("Edax does not skip the search: Level %d@%d < %d@%d\n", hash_data->depth,selectivity_table[hash_data->selectivity].percent, search->depth, selectivity_table[search->selectivity].percent);
559 } else {
560 cassio_debug("Edax does not skip the search: unsolved score alpha %d < beta %d\n", alpha, beta);
561 }
562 }
563 } else {
564 cassio_debug("Edax does not skip the search: Position %s (hash=%llx) not found\n", board_to_string(board, search->player, b), board_get_hash_code(board));
565 }
566
567 return false;
568}
569
570
585double engine_midgame_search(void *v, const char *position, const double alpha, const double beta, const int depth, const int precision)
586{
587 Engine *engine = (Engine*) v;
588 Search *search = engine->search;
589 Board board[1];
590 int player;
591 int old_score;
592
593 if (search == NULL) {
594 engine_send("ERROR: Engine need to be initialized.");
595 return -SCORE_INF;
596 }
597
598 engine->is_searching = true;
599 player = board_set(board, position);
600
601 old_score = engine_open(search, board, player, floor(alpha), ceil(beta), depth, precision);
602
603 if (skip_search(engine, &old_score)) {
604 } else if (is_position_new(engine, board)) {
605 cassio_debug("iterative deepening.\n");
607 } else {
608 cassio_debug("aspiration search.\n");
609 aspiration_search(search, options.alpha, options.beta, search->depth, old_score);
610 }
611
612 engine_close(search);
613 engine->is_searching = false;
614
615 return search->result->score * 1.0f;
616}
617
630int engine_endgame_search(void *v, const char *position, const int alpha, const int beta, const int precision)
631{
632 Engine *engine = (Engine*) v;
633 Search *search = engine->search;
634 Board board[1];
635 int player;
636 int old_score;
637 int depth;
638
639 if (search == NULL) {
640 engine_send("ERROR: Engine need to be initialized.");
641 return -SCORE_INF;
642 }
643
644 engine->is_searching = true;
645 player = board_set(board, position);
646 depth = board_count_empties(board);
647
648 old_score = engine_open(search, board, player, alpha, beta, depth, precision);
649
650 if (skip_search(engine, &old_score)) {
651 } else if (is_position_new(engine, board)) {
652 cassio_debug("iterative deepening.\n");
654 } else {
655 cassio_debug("aspiration search.\n");
656 aspiration_search(search, options.alpha, options.beta, search->depth, old_score);
657 }
658
659 engine_close(search);
660 engine->is_searching = false;
661
662 return search->result->score;
663}
664
670void engine_stop(void *v)
671{
672 Search *search = (Search*) v;
673 if (search == NULL) {
674 engine_send("ERROR: Engine need to be initialized.");
675 return;
676 }
678}
679
683void engine_loop(void)
684{
685 char *cmd = NULL, *param = NULL;
686 Engine *engine = (Engine*) engine_init();
687
688 // loop forever
689 for (;;) {
690 errno = 0;
691
692 engine_wait_input(engine, &cmd, &param);
693
694 if (cmd == NULL || *cmd == '\0') {
695
696 } else if (strcmp(cmd, "init") == 0) {
697 engine_send("ready.");
698
699 } else if (strcmp(cmd, "get-version") == 0) {
700 engine_send("version: Edax %s", VERSION_STRING);
701 engine_send("ready.");
702
703 } else if (strcmp(cmd, "new-position") == 0) {
704 engine->last_position.n = 0;
705 engine_send("ready.");
706
707 } else if (strcmp(cmd, "feed-hash") == 0) {
708 int depth = 21, precision = 73, player;
709 double lower = -SCORE_INF, upper = SCORE_INF;
710 Board board[1];
711 Line pv[1];
712 char *string;
713
714 errno = 0;
715 string = parse_board(param, board, &player);
716 if (string == param) engine_send("Error: in feed-hash, Edax cannot parse position.");
717 else {
718 string = parse_real(string, &lower);
719 if (errno) engine_send("Error: in feed-hash, Edax cannot parse lower.");
720 else {
721 string = parse_real(string, &upper);
722 if (errno) engine_send("Error: in feed-hash, Edax cannot parse upper.");
723 else {
724 string = parse_int(string, &depth);
725 if (errno) engine_send("Error: in feed-hash, Edax cannot parse depth.");
726 else {
727 string = parse_int(string, &precision);
728 if (errno) engine_send("Error: in feed-hash, Edax cannot parse precision.");
729 else {
730 line_init(pv, player);
731 parse_game(string, board, pv);
732 engine_feed_hash(engine, board, floor(lower), ceil(upper), depth, precision, pv);
733 }
734 }
735 }
736 }
737 }
738
739 } else if (strcmp(cmd, "empty-hash") == 0) {
740 engine_empty_hash(engine);
741
742 } else if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "eof") == 0) {
743 engine_free(engine->search);
744 event_free(engine->event);
745 free(engine);
746 free(cmd);
747 free(param);
748 engine_send("bye bye.");
749 return;
750
751 } else if (strcmp(cmd, "midgame-search") == 0) {
752 double alpha = -SCORE_INF, beta = SCORE_INF;
753 int player, depth = 60, precision = 100;
754 Board board[1];
755 char b[80];
756 char *s;
757
758 errno = 0;
759 s = parse_board(param, board, &player);
760 if (s == param) engine_send("ERROR: midgame-search cannot parse position.");
761 else {
762 s = parse_real(s, &alpha);
763 if (errno) engine_send("ERROR: midgame-search cannot parse alpha.");
764 else {
765 s = parse_real(s, &beta);
766 if (errno) engine_send("ERROR: midgame_search cannot parse beta.");
767 else {
768 s = parse_int(s, &depth);
769 if (errno) engine_send("ERROR: midgame_search cannot parse depth.");
770 else {
771 s = parse_int(s, &precision);
772 if (errno) engine_send("ERROR: midgame_search cannot parse precision.");
773 engine_midgame_search(engine, board_to_string(board, player, b), alpha, beta, depth, precision);
774 }
775 }
776 }
777 }
778 engine_send("ready.");
779
780 } else if (strcmp(cmd, "endgame-search") == 0) {
781 int alpha = -SCORE_INF, beta = SCORE_INF;
782 int player, precision = 100;
783 Board board[1];
784 char b[80];
785 char *s;
786
787 errno = 0;
788 s = parse_board(param, board, &player);
789 if (s == param) engine_send("ERROR: endgame_search cannot parse position.");
790 else {
791 s = parse_int(s, &alpha);
792 if (errno) engine_send("ERROR: endgame_search cannot parse alpha.");
793 else {
794 s = parse_int(s, &beta);
795 if (errno) engine_send("ERROR: endgame_search cannot parse beta.");
796 else {
797 s = parse_int(s, &precision);
798 if (errno) engine_send("ERROR: endgame_search cannot parse precision.");
799 engine_endgame_search(engine, board_to_string(board, player, b), alpha, beta, precision);
800 }
801 }
802 }
803 engine_send("ready.");
804
805 // ERROR: unknown message
806 } else {
807 engine_send("ERROR: unknown command %s", cmd);
808 engine_send("ready.");
809 }
810 }
811}
812
unsigned long long board_get_hash_code(const Board *board)
Compute a hash code.
Definition board.c:1134
void board_restore(Board *board, const Move *move)
Restore a board.
Definition board.c:487
void board_update(Board *board, const Move *move)
Update a board.
Definition board.c:469
int board_count_empties(const Board *board)
Check if the game is over.
Definition board.c:1216
int get_stability(const unsigned long long P, const unsigned long long O)
Estimate the stability.
Definition board.c:1067
char * board_to_string(const Board *board, const int player, char *s)
convert the to a compact string.
Definition board.c:1272
bool board_is_pass(const Board *board)
Check if current player should pass.
Definition board.c:1191
bool board_equal(const Board *b1, const Board *b2)
Compare two board for equality.
Definition board.c:335
int board_set(Board *board, const char *string)
Set a board from a string description.
Definition board.c:154
void board_pass(Board *board)
Passing move.
Definition board.c:503
void engine_stop(void *v)
Stop searching.
Definition cassio.c:670
static void engine_close(Search *search)
Finalize search.
Definition cassio.c:355
static void engine_wait_input(Engine *engine, char **cmd, char **param)
Engine wait input.
Definition cassio.c:157
void engine_loop(void)
Loop event.
Definition cassio.c:683
static Search * engine_create_search(void)
Create engine search.
Definition cassio.c:238
void feed_all_hash_table(Search *search, Board *board, const int depth, const int selectivity, const int lower, const int upper, const int move)
Definition cassio.c:414
Log engine_log[1]
Definition cassio.c:35
struct Engine Engine
void * engine_init(void)
Create a new Othello engine.
Definition cassio.c:376
int engine_endgame_search(void *v, const char *position, const int alpha, const int beta, const int precision)
Endgame search.
Definition cassio.c:630
double engine_midgame_search(void *v, const char *position, const double alpha, const double beta, const int depth, const int precision)
Midgame search.
Definition cassio.c:585
static char last_line_sent[1024]
Definition cassio.c:42
static bool is_position_new(Engine *engine, Board *board)
Definition cassio.c:186
static void * engine_input_loop(void *v)
Read event loop.
Definition cassio.c:167
static char engine_result[1024]
Definition cassio.c:40
#define ENGINE_N_POSITION
Definition cassio.c:37
static bool skip_search(Engine *engine, int *old_score)
Check if a search has already been done here.
Definition cassio.c:520
static int engine_open(Search *search, const Board *board, const int player, const int alpha, const int beta, const int depth, const int precision)
Open search engine.
Definition cassio.c:268
static void engine_get_input(Engine *engine)
Read an input line.
Definition cassio.c:86
void engine_empty_hash(void *v)
Empty (ie completely clear) the engine hash table.
Definition cassio.c:501
void engine_free(void *v)
free resources allocated
Definition cassio.c:402
static void engine_observer(Result *result)
Call back function use by search to print its results.
Definition cassio.c:214
void engine_feed_hash(void *v, Board *board, int lower, int upper, const int depth, const int precision, Line *pv)
feed hash table
Definition cassio.c:433
static void engine_send(const char *format,...)
Send a message on stdout.
Definition cassio.c:61
#define SCORE_MAX
Definition const.h:58
#define SCORE_INF
Definition const.h:52
@ PASS
Definition const.h:37
@ NOMOVE
Definition const.h:37
#define VERSION_STRING
Definition const.h:88
@ WHITE
Definition const.h:43
@ BLACK
Definition const.h:42
@ RUNNING
Definition const.h:71
@ STOP_ON_DEMAND
Definition const.h:75
@ STOP_END
Definition const.h:76
@ PV_NODE
Definition const.h:81
#define SCORE_MIN
Definition const.h:55
void event_clear_messages(Event *event)
Remove all unprocessed messages.
Definition event.c:45
void event_init(Event *event)
Initialize a message event.
Definition event.c:23
void event_wait(Event *event, char **cmd, char **param)
Wait input.
Definition event.c:133
void event_free(Event *event)
Free a message event.
Definition event.c:67
void event_add_message(Event *event, char *message)
Add a new message at the bottom of the list.
Definition event.c:93
bool hash_get(HashTable *hash_table, const unsigned long long hash_code, HashData *data)
Find an hash table entry according to the evaluated board hash codes.
Definition hash-lock-free.c:600
void hash_clear(HashTable *hash_table)
Clear the hashtable.
Definition hash-lock-free.c:179
void hash_feed(HashTable *hash_table, const unsigned long long hash_code, const int depth, const int selectivity, const int lower, const int upper, const int move)
Feed hash table (from Cassio).
Definition hash-lock-free.c:496
void hash_cleanup(HashTable *hash_table)
Clear the hashtable.
Definition hash-lock-free.c:159
bool movelist_is_empty(const MoveList *movelist)
Check if the list is empty.
Definition move.c:537
void movelist_sort(MoveList *movelist)
Sort all moves.
Definition move.c:505
Move * movelist_first(MoveList *movelist)
Return the first move of the list.
Definition move.c:422
void line_init(Line *line, const int player)
Initialize a sequence of moves.
Definition move.c:549
void movelist_evaluate(MoveList *movelist, Search *search, const HashData *hash_data, const int alpha, const int depth)
Evaluate a list of move in order to sort it.
Definition move.c:436
int movelist_get_moves(MoveList *movelist, const Board *board)
Get moves from a position.
Definition move.c:298
char * line_to_string(const Line *line, int n, const char *separator, char *string)
Line to string.
Definition move.c:635
char * move_to_string(const int x, const int player, char *s)
Print out a move.
Definition move.c:76
Move * movelist_sort_bestmove(MoveList *movelist, const int move)
Sort a move as best.
Definition move.c:468
#define foreach_move(iter, movelist)
Definition move.h:78
Options options
Definition options.c:22
void iterative_deepening(Search *search, int alpha, int beta)
Iterative deepening.
Definition root.c:621
bool is_pv_ok(Search *search, int bestmove, int search_depth)
Check if PV is ok.
Definition root.c:83
int aspiration_search(Search *search, int alpha, int beta, const int depth, int score)
Aspiration window.
Definition root.c:451
void record_best_move(Search *search, const Board *init_board, const Move *bestmove, const int alpha, const int beta, const int depth)
Record best move.
Definition root.c:150
void search_time_init(Search *search)
Initialize the alloted time.
Definition search.c:697
void search_init(Search *search)
Init the main search.
Definition search.c:351
void search_free(Search *search)
Free the search allocated ressource.
Definition search.c:441
const Selectivity selectivity_table[]
Definition search.c:97
unsigned long long search_count_nodes(Search *search)
Return the number of nodes searched.
Definition search.c:1073
int get_pv_extension(const int depth, const int n_empties)
Compute the pv_extension.
Definition search.c:1012
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_stop_all(Search *search, const Stop stop)
Stop the search.
Definition search.c:1335
long long search_time(Search *search)
Return the time spent by the search.
Definition search.c:1061
void statistics_sum_nodes(Search *search)
Cumulate node counts from the last search.
Definition stats.c:97
Statistics header.
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
Definition search.h:35
int lower
Definition search.h:36
int upper
Definition search.h:37
Definition cassio.c:45
bool is_searching
Definition cassio.c:52
Search * search
Definition cassio.c:47
Event event[1]
Definition cassio.c:46
struct Engine::@4 last_position
Board board[ENGINE_N_POSITION]
Definition cassio.c:49
int n
Definition cassio.c:50
Definition event.h:18
Thread thread
Definition event.h:24
volatile bool loop
Definition event.h:19
Definition hash.h:24
unsigned char move[2]
Definition hash.h:31
signed char lower
Definition hash.h:29
signed char upper
Definition hash.h:30
unsigned char selectivity
Definition hash.h:26
unsigned char depth
Definition hash.h:25
Definition move.h:35
int n_moves
Definition move.h:37
char move[GAME_SIZE]
Definition move.h:36
LogFile.
Definition util.h:423
FILE * f
Definition util.h:424
Definition move.h:29
int n_moves
Definition move.h:31
Definition move.h:20
int score
Definition move.h:23
int x
Definition move.h:22
char * ui_log_file
Definition options.h:78
int alpha
Definition options.h:52
bool transgress_cassio
Definition options.h:38
int beta
Definition options.h:53
Definition search.h:41
bool book_move
Definition search.h:50
int move
Definition search.h:44
unsigned long long n_nodes
Definition search.h:49
int score
Definition search.h:45
long long time
Definition search.h:48
int n_moves_left
Definition search.h:52
int selectivity
Definition search.h:43
Line pv[1]
Definition search.h:47
int depth
Definition search.h:42
int n_moves
Definition search.h:51
Bound bound[BOARD_SIZE+2]
Definition search.h:46
Definition search.h:95
struct Search::@24 time
volatile long long spent
Definition search.h:126
int n_empties
Definition search.h:99
bool keep_date
Definition search.h:143
volatile unsigned long long child_nodes
Definition search.h:156
MoveList movelist[1]
Definition search.h:132
Result * result
Definition search.h:151
int depth_pv_extension
Definition search.h:121
int height
Definition search.h:133
int player
Definition search.h:100
struct Search::@25 options
int depth
Definition search.h:117
Bound stability_bound
Definition search.h:135
HashTable pv_table[1]
Definition search.h:104
HashTable hash_table[1]
Definition search.h:103
volatile Stop stop
Definition search.h:122
volatile unsigned long long n_nodes
Definition search.h:155
HashTable shallow_table[1]
Definition search.h:105
int selectivity
Definition search.h:118
NodeType node_type[GAME_SIZE]
Definition search.h:134
Board board[1]
Definition search.h:96
int percent
Definition search.h:28
void time_stamp(FILE *f)
Print local time.
Definition util.c:189
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
void thread_create2(Thread *thread, void *(*function)(void *), void *data)
Create a thread.
Definition util.c:922
long long(* time_clock)(void)
Time clock.
Definition util.c:122
void string_to_lowercase(char *s)
Change all char of a string to lowercase.
Definition util.c:355
char * parse_real(const char *string, double *result)
Parse a real number (as a double floating point).
Definition util.c:796
char * string_read_line(FILE *f)
Read a line.
Definition util.c:265
char * parse_word(const char *string, char *word, unsigned int n)
Parse a word.
Definition util.c:562
char * parse_game(const char *string, const Board *board_init, Line *line)
Parse a sequence of moves.
Definition util.c:657
char * parse_board(const char *string, Board *board, int *player)
Parse a board.
Definition util.c:682
Miscellaneous utilities header.
#define log_close(l)
Close an opened log file.
Definition util.h:435
#define MIN(a, b)
Definition util.h:101
#define cassio_debug(...)
Display a message in cassio's "fenetre de rapport" .
Definition util.h:389
#define log_open(l, file)
open a log file if allowed.
Definition util.h:429
#define log_is_open(l)
Check if the log stream can be used.
Definition util.h:448
#define BOUND(var, min, max, name)
Definition util.h:104
Parallel search header.