My Project
perft.c
Go to the documentation of this file.
1
11#include "bit.h"
12#include "board.h"
13#include "move.h"
14#include "hash.h"
15#include "options.h"
16#include "settings.h"
17#include "util.h"
18#include "perft.h"
19
20#include <stdlib.h>
21#include <math.h>
22
26typedef struct {
27 unsigned long long n_moves; /*< move number */
28 unsigned long long n_draws; /*< number of draws */
29 unsigned long long n_losses; /*< number of losses */
30 unsigned long long n_wins; /*< number of wins */
31 unsigned long long n_passes; /*< number of passes */
32 unsigned int min_mobility; /*< min mobility */
33 unsigned int max_mobility; /*< max mobility */
35
37const GameStatistics GAME_STATISTICS_INIT = {0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 64, 0};
38
45{
46 global->n_moves += local->n_moves;
47 global->n_draws += local->n_draws;
48 global->n_losses += local->n_losses;
49 global->n_wins += local->n_wins;
50 global->n_passes += local->n_passes;
51 if (global->min_mobility > local->min_mobility) global->min_mobility = local->min_mobility;
52 if (global->max_mobility < local->max_mobility) global->max_mobility = local->max_mobility;
53}
54
55
63static void count_game(const Board *board, const int depth, GameStatistics *global_stats)
64{
66 unsigned long long moves;
67 int x;
68 Board next[1];
69
70 if (depth == 1) {
71 moves = get_moves(board->player, board->opponent);
72 stats.n_moves = stats.max_mobility = stats.min_mobility = bit_count(moves);
73 if (moves == 0) {
74 if (can_move(board->opponent, board->player)) {
75 stats.n_passes = 1;
76 } else {
77 const int n_player = bit_count(board->player);
78 const int n_opponent = bit_count(board->opponent);
79 if (n_player > n_opponent) stats.n_wins = 1;
80 else if (n_player == n_opponent) stats.n_draws = 1;
81 else stats.n_losses = 1;
82 }
83 }
84 } else {
85 moves = get_moves(board->player, board->opponent);
86 if (moves) {
87 foreach_bit (x, moves) {
88 board_next(board, x, next);
89 count_game(next, depth - 1, &stats);
90 }
91 } else {
92 board_next(board, PASS, next);
93 if (can_move(next->player, next->opponent)) {
94 count_game(next, depth - 1, &stats);
95 }
96 }
97 }
98 game_statistics_cumulate(global_stats, &stats);
99}
100
107void count_games(const Board *board, const int depth)
108{
109 int i;
110 unsigned long long t, n;
111 GameStatistics stats;
112
113 board_print(board, BLACK, stdout);
114 puts("\n ply moves passes wins draws losses mobility time speed");
115 puts("------------------------------------------------------------------------------------------------------------------");
116 n = 1;
117 for (i = 1; i <= depth; ++i) {
118 stats = GAME_STATISTICS_INIT;
119 t = -cpu_clock();
120 count_game(board, i, &stats);
121 t += cpu_clock();
122 printf(" %2d, %15llu, %12llu, %12llu, %12llu, %12llu, ", i, stats.n_moves + stats.n_passes, stats.n_passes, stats.n_wins, stats.n_draws, stats.n_losses);
123 printf(" %2d - %2d, ", stats.min_mobility, stats.max_mobility);
124 n += stats.n_moves + stats.n_passes;
125 time_print(t, true, stdout); printf(", ");
126 print_scientific(n / (0.001 * t + 0.001), "N/s\n", stdout);
127 if (stats.n_moves + stats.n_passes == 0) break;
128 }
129 printf("Total %12llu\n", n);
130 puts("------------------------------------------------------------------------------------------------------------------");
131}
132
142static void estimate_game(const Board *board, const int depth, Random *r, double *n)
143{
144 unsigned long long moves;
145 int x, i, j, k;
146 Board next[1];
147
148 moves = get_moves(board->player, board->opponent);
149 i = bit_count(moves);
150 if (i == 0 && !can_move(board->opponent, board->player)) {
151 n[depth] = 0;
152 } else {
153 n[depth] = 1;
154 if (i == 0) {
155 board_next(board, PASS, next);
156 estimate_game(next, depth + 1, r, n);
157 } else {
158 j = random_get(r) % i;
159 foreach_bit (x, moves) {
160 if (j == 0) {
161 board_next(board, x, next);
162 estimate_game(next, depth + 1, r, n);
163 for (k = depth; n[k]; ++k) n[k] *= i;
164 break;
165 } else --j;
166 }
167 }
168 }
169}
170
177void estimate_games(const Board *board, const long long n)
178{
179 int i, j;
180 unsigned long long t;
181 double x[128], m[128], s[128], em[128], es[128], en[128];
182 double M, S, EM, ES;
183 Random r;
184
185 t = -cpu_clock();
186 random_seed(&r, real_clock());
187 M = S = EM = ES = 0.0;
188 for (i = 0; i < 128; ++i) m[i] = s[i] = 0.0;
189 for (i = 0; i < 128; ++i) em[i] = es[i] = en[i] = 0.0;
190
191 board_print(board, BLACK, stdout);
192 for (j = 1; j <= n; ++j) {
193 for (i = 0; i < 128; ++i) x[i] = 0.0;
194 estimate_game(board, 1, &r, x);
195 for (i = 1; x[i]; ++i) {
196 m[i] += x[i]; s[i] += x[i] * x[i];
197 M += x[i]; S += x[i] * x[i];
198 }
199 {
200 em[i] += x[i - 1]; es[i] += x[i - 1] * x[i - 1];
201 EM += x[i - 1]; ES += x[i - 1] * x[i - 1];
202 en[i]++;
203 }
204 }
205 t += cpu_clock();
206
207 for (i = 1; m[i] || en[i]; ++i) {
208 m[i] /= n;
209 s[i] = sqrt((s[i] / n - m[i] * m[i])/n);
210 printf("%2d: %e +/- %e; ", i, m[i], s[i]);
211
212 if (en[i]) {
213 em[i] /= n;
214 es[i] = sqrt((es[i] / n - em[i] * em[i])/n);
215 printf("%e +/- %e;", em[i], es[i]);
216 }
217 putchar('\n');
218 }
219 M /= n;
220 S = sqrt((S / n - M * M)/n);
221 EM /= n;
222 ES = sqrt((ES / n - EM * EM)/n);
223 printf("Total %e +/- %e: %e +/- %e en", M, S, EM, ES);
224 time_print(t, false, stdout); printf("\n");
225}
226
239static void test_mobility(const Board *board, const int ply, Random *r, int *move, int *max_mobility, int *max_empties, const unsigned long long n)
240{
241 unsigned long long moves;
242 int x, i, k, e;
243 Board next[1];
244
245 e = board_count_empties(board);
246
247 if (e > *max_mobility) {
248 moves = get_moves(board->player, board->opponent);
249 if (moves) {
250 i = bit_count(moves);
251 if (i > *max_mobility || (i == *max_mobility && e > *max_empties)) {
252 *max_mobility = i;
253 *max_empties = e;
254 printf("\n after %llu trials:\n\n", n);
255 board_print(board, ply % 2, stdout);
256 for (k = 1; k < ply; ++k) {
257 move_print(move[k], k % 2, stdout);
258 putchar(' ');
259 }
260 putchar('\n');
261 }
262 moves &= 0x007e7e7e7e7e7e00ULL;
263 if (moves) {
264 i = random_get(r) % bit_count(moves);
265 foreach_bit (x, moves) {
266 if (i-- == 0) {
267 move[ply] = x;
268 board_next(board, x, next);
269 test_mobility(next, ply + 1, r, move, max_mobility, max_empties, n);
270 break;
271 }
272 }
273 }
274 } else {
275 if (can_move(board->opponent, board->player)) {
276 move[ply] = PASS;
277 board_next(board, PASS, next);
278 test_mobility(next, ply + 1, r, move, max_mobility, max_empties, n);
279 }
280 }
281 }
282}
283
290void seek_highest_mobility(const Board *board, const unsigned long long t)
291{
292 int max_mobility = get_mobility(board->player, board->opponent);
293 int max_empties = board_count_empties(board);
294 const long long t_max = t * 1000 + cpu_clock();
295 int i;
296 unsigned long long n = 0;
297 const int bucket = 10000;
298 int x[128];
299 Random r;
300
301 random_seed(&r, real_clock());
302
303 while (cpu_clock() < t_max) {
304 i = bucket;
305 while (i-- > 0) {
306 test_mobility(board, 1, &r, x, &max_mobility, &max_empties, ++n);
307 }
308 }
309}
310
319
321const GameHash GAME_HASH_INIT = {{0ULL, 0ULL}, {0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 64, 0}, 0};
322
324typedef struct {
326 int size;
327 int mask;
328 unsigned long long n_tries;
329 unsigned long long n_hits;
331
338static void gamehash_init(GameHashTable *hash, int bitsize)
339{
340 int i;
341
342 hash->size = (1 << bitsize) + 3;
343 hash->mask = (1 << bitsize) - 1;
344 hash->array = (GameHash*) malloc((hash->size) * sizeof (GameHash));
345 if (hash->array == NULL) fatal_error("Cannot allocate qperft hashtable.\n");
346 for (i = 0; i < hash->size; ++i) hash->array[i] = GAME_HASH_INIT;
347 hash->n_tries = hash->n_hits = 0;
348}
349
356{
357 free(hash->array);
358}
359
368static void gamehash_store(GameHashTable *hash, const Board *b, const int depth, const GameStatistics *stats)
369{
370 Board u;
371 GameHash *i, *j;
372
373 if (depth > 2) {
374 board_unique(b, &u);
375 i = j = hash->array + (board_get_hash_code(&u) & hash->mask);
376
377 ++j; if (i->stats.n_moves > j->stats.n_moves) i = j;
378 ++j; if (i->stats.n_moves > j->stats.n_moves) i = j;
379 ++j; if (i->stats.n_moves > j->stats.n_moves) i = j;
380 i->board = u;
381 i->stats = *stats;
382 i->depth = depth;
383 }
384}
385
395static bool gamehash_fail(GameHashTable *hash, const Board *b, const int depth, GameStatistics *stats)
396{
397 Board u;
398 GameHash *i, *j;
399
400 if (depth > 2) {
401
402 board_unique(b, &u);
403 j = hash->array + (board_get_hash_code(&u) & hash->mask);
404 ++hash->n_tries;
405
406 for (i = j; i < j + 4; ++i) {
407 if (depth == i->depth && i->board.player == u.player && i->board.opponent == u.opponent) {
408 *stats = i->stats;
409 ++hash->n_hits;
410 return false;
411 }
412 }
413
414 }
415
416 return true;
417}
418
419
428static void quick_count_game_6x6(GameHashTable *hash, const Board *board, const int depth, GameStatistics *global_stats)
429{
431 unsigned long long moves;
432 int x;
433 Board next[1];
434
435 if (depth == 1) {
436 moves = get_moves_6x6(board->player, board->opponent);
437 stats.n_moves = stats.max_mobility = stats.min_mobility = bit_count(moves);
438 if (moves == 0) {
439 if (can_move_6x6(board->opponent, board->player)) {
440 stats.n_passes = 1;
441 } else {
442 const int n_player = bit_count(board->player);
443 const int n_opponent = bit_count(board->opponent);
444 if (n_player > n_opponent) stats.n_wins = 1;
445 else if (n_player == n_opponent) stats.n_draws = 1;
446 else stats.n_losses = 1;
447 }
448 }
449 } else if (gamehash_fail(hash, board, depth, &stats)) {
450 moves = get_moves_6x6(board->player, board->opponent);
451 if (moves) {
452 foreach_bit (x, moves) {
453 board_next(board, x, next);
454 quick_count_game_6x6(hash, next, depth - 1, &stats);
455 }
456 } else {
457 board_next(board, PASS, next);
458 if (can_move_6x6(next->player, next->opponent)) {
459 quick_count_game_6x6(hash, next, depth - 1, &stats);
460 }
461 }
462 gamehash_store(hash, board, depth, &stats);
463 }
464 game_statistics_cumulate(global_stats, &stats);
465}
466
475static void quick_count_game(GameHashTable *hash, const Board *board, const int depth, GameStatistics *global_stats)
476{
478 unsigned long long moves;
479 int x;
480 Board next[1];
481
482 if (depth == 1) {
483 moves = get_moves(board->player, board->opponent);
484 stats.n_moves = stats.max_mobility = stats.min_mobility = bit_count(moves);
485 if (moves == 0) {
486 if (can_move(board->opponent, board->player)) {
487 stats.n_passes = 1;
488 } else {
489 const int n_player = bit_count(board->player);
490 const int n_opponent = bit_count(board->opponent);
491 if (n_player > n_opponent) stats.n_wins = 1;
492 else if (n_player == n_opponent) stats.n_draws = 1;
493 else stats.n_losses = 1;
494 }
495 }
496 } else if (gamehash_fail(hash, board, depth, &stats)) {
497 moves = get_moves(board->player, board->opponent);
498 if (moves) {
499 foreach_bit (x, moves) {
500 board_next(board, x, next);
501 quick_count_game(hash, next, depth - 1, &stats);
502 }
503 } else {
504 board_next(board, PASS, next);
505 if (can_move(next->player, next->opponent)) {
506 quick_count_game(hash, next, depth - 1, &stats);
507 }
508 }
509 gamehash_store(hash, board, depth, &stats);
510 }
511 game_statistics_cumulate(global_stats, &stats);
512}
513
521void quick_count_games(const Board *board, const int depth, const int size)
522{
523 int i;
524 long long t;
525 GameHashTable hash;
526 GameStatistics stats;
527 unsigned long long n;
528
529 board_print(board, BLACK, stdout);
530 puts("\n ply moves passes wins draws losses mobility time speed");
531 puts("------------------------------------------------------------------------------------------------------------------");
532 n = 1;
533 for (i = 1; i <= depth; ++i) {
534 t = -cpu_clock();
536 stats = GAME_STATISTICS_INIT;
537 if (size == 6) quick_count_game_6x6(&hash, board, i, &stats);
538 else quick_count_game(&hash, board, i, &stats);
539 t += cpu_clock();
540 printf(" %2d, %15llu, %12llu, %12llu, %12llu, %12llu, ", i, stats.n_moves + stats.n_passes, stats.n_passes, stats.n_wins, stats.n_draws, stats.n_losses);
541 printf(" %2d - %2d, ", stats.min_mobility, stats.max_mobility);
542 time_print(t, true, stdout); printf(", ");
543 n += stats.n_moves + stats.n_passes;
544 print_scientific(n / (0.001 * t + 0.001), "moves/s,", stdout);
545 printf(" (h_tries = %lld, h_hits = %lld)\n", hash.n_tries, hash.n_hits);
546 gamehash_delete(&hash);
547 if (stats.n_moves + stats.n_passes == 0) break;
548 }
549 printf("Total %12llu\n", n);
550 puts("------------------------------------------------------------------------------------------------------------------");
551}
552
553
557#pragma pack(1)
558typedef struct CBoard {
559 unsigned char x[13];
561#pragma pack()
562
563static void compact_board(const Board *b, CBoard *c) {
564 int i, n = 0, x;
565
566 i = 0;
567 for (x = A1; x <= H8; ++x) {
568 if (x % 5 == 0) n = 0;
569 n = 3 * n + board_get_square_color(b, x);
570 if (x % 5 == 4) c->x[i++] = n;
571 }
572 c->x[i] = n;
573}
574
575
579typedef struct PosArray {
581 int n;
582 int size;
584
589static void positionarray_init(PosArray *array)
590{
591 array->item = NULL;
592 array->n = array->size = 0;
593}
594
600{
601 free(array->item);
602}
603
610static bool positionarray_append(PosArray *array, const CBoard *b)
611{
612 int i;
613 for (i = 0; i < array->n; ++i) {
614 if (memcmp(array->item + i, b, 13) == 0) return false;
615 }
616
617 if (array->size < array->n + 1) {
618 array->item = (CBoard*) realloc(array->item, (array->size = (array->size + 1)) * sizeof (CBoard));
619 if (array->item == NULL) fatal_error("Cannot re-allocate board array.\n");
620 }
621 array->item[array->n++] = *b;
622 return true;
623}
624
628typedef struct {
630 int size;
631 int mask;
632} BoardCache;
633
639static void boardcache_init(BoardCache *hash, int bitsize)
640{
641 int i;
642
643 hash->size = (1 << bitsize) + 3;
644 hash->mask = (1 << bitsize) - 1;
645 hash->array = (Board *) malloc(hash->size * sizeof (Board));
646 if (hash->array == NULL) fatal_error("Cannot re-allocate board array.\n");
647 for (i = 0; i < hash->size; ++i) hash->array[i].player = hash->array[i].opponent = -1ULL;
648}
649
655{
656 free(hash->array);
657}
658
664static bool boardcache_undone(BoardCache *hash, const Board *b)
665{
666 Board u;
667 unsigned long long h;
668 int i;
669
670 board_unique(b, &u);
671 h = board_get_hash_code(&u);
672 i = (h & hash->mask);
673 if (board_compare(&u, hash->array + i) == 0
674 || board_compare(&u, hash->array + i + 1) == 0
675 || board_compare(&u, hash->array + i + 2) == 0
676 || board_compare(&u, hash->array + i + 3) == 0) return false;
677
678 return true;
679}
680
681
682static void boardcache_append(BoardCache *hash, const Board *b)
683{
684 Board u;
685 unsigned long long h;
686 int i, j, k, l;
687
688 board_unique(b, &u);
689 h = board_get_hash_code(&u);
690 i = (h & hash->mask);
691 if (board_compare(&u, hash->array + i) == 0
692 || board_compare(&u, hash->array + i + 1) == 0
693 || board_compare(&u, hash->array + i + 2) == 0
694 || board_compare(&u, hash->array + i + 3) == 0) return;
695
696 l = board_count_empties(hash->array + i); j = i;
697 k = board_count_empties(hash->array + ++i); if (k > l) {l = k; j = i;}
698 k = board_count_empties(hash->array + ++i); if (k > l) {l = k; j = i;}
699 k = board_count_empties(hash->array + ++i); if (k > l) {l = k; j = i;}
700
701 hash->array[j] = u;
702}
703
709void positionhash_init(PositionHash *hash, int bitsize)
710{
711 int i;
712
713 hash->size = (1 << bitsize);
714 hash->mask = hash->size - 1;
715 hash->array = (PosArray*) malloc(hash->size * sizeof (PosArray));
716 if (hash->array == NULL) fatal_error("Cannot re-allocate board array.\n");
717 for (i = 0; i < hash->size; ++i) positionarray_init(hash->array + i);
718}
719
725{
726 int i;
727
728 for (i = 0; i < hash->size; ++i) positionarray_delete(hash->array + i);
729 free(hash->array);
730}
731
739{
740 Board u;
741 CBoard c;
742 unsigned long long h;
743
744 board_unique(b, &u);
745 compact_board(&u, &c);
746 h = board_get_hash_code(&u);
747 return positionarray_append(hash->array + (h & hash->mask), &c);
748}
749
757static unsigned long long count_position(PositionHash *hash, BoardCache *cache, const Board *board, const int depth)
758{
759 unsigned long long nodes = 0;
760 unsigned long long moves;
761 int x;
762 Board next[1];
763
764 if (boardcache_undone(cache, board)) {
765 if (depth == 0) return positionhash_append(hash, board);
766 moves = get_moves(board->player, board->opponent);
767
768 if (moves) {
769 foreach_bit (x, moves) {
770 board_next(board, x, next);
771 nodes += count_position(hash, cache, next, depth - 1);
772 }
773 } else if (can_move(board->opponent, board->player)) {
774 board_next(board, PASS, next);
775 nodes += count_position(hash, cache, next, depth);
776 }
777 boardcache_append(cache, board);
778 }
779
780 return nodes;
781}
782
790static unsigned long long count_position_6x6(PositionHash *hash, BoardCache *cache, const Board *board, const int depth)
791{
792 unsigned long long nodes = 0;
793 unsigned long long moves;
794 int x;
795 Board next[1];
796
797 if (boardcache_undone(cache, board)) {
798 if (depth == 0) return positionhash_append(hash, board);
799 moves = get_moves_6x6(board->player, board->opponent);
800
801 if (moves) {
802 foreach_bit (x, moves) {
803 board_next(board, x, next);
804 nodes += count_position_6x6(hash, cache, next, depth - 1);
805 }
806 } else if (can_move_6x6(board->opponent, board->player)) {
807 board_next(board, PASS, next);
808 nodes += count_position_6x6(hash, cache, next, depth);
809 }
810 boardcache_append(cache, board);
811 }
812
813 return nodes;
814}
815
822void count_positions(const Board *board, const int depth, const int size)
823{
824 int i;
825 unsigned long long n, c;
826 long long t;
827 PositionHash hash;
828 BoardCache cache;
829
830
831 board_print(board, BLACK, stdout);
832 puts("\n discs nodes total time speed");
833 puts("----------------------------------------------------------");
834 c = 0;
835 for (i = 0; i <= depth; ++i) {
838 t = -cpu_clock();
839 if (size == 6) c += (n = count_position_6x6(&hash, &cache, board, i));
840 else c += (n = count_position(&hash, &cache, board, i));
841 t += cpu_clock();
842 printf(" %2d, %12llu, %12llu, ", i + 4, n, c);
843 time_print(t, true, stdout); printf(", ");
844 print_scientific(c / (0.001 * t + 0.001), "N/s\n", stdout);
845 positionhash_delete(&hash);
846 boardcache_delete(&cache);
847 }
848 puts("----------------------------------------------------------");
849}
850
851
858unsigned long long shape_unique(unsigned long long shape)
859{
860 unsigned long long sym, unique;
861 int i;
862
863 unique = shape;
864 for (i = 1; i < 8; ++i) {
865 sym = shape;
866 if (i & 1) sym = horizontal_mirror(sym);
867 if (i & 2) sym = vertical_mirror(sym);
868 if (i & 4) sym = transpose(sym);
869 if (unique > sym) unique = sym;
870 }
871
872 return unique;
873}
874
881unsigned long long shape_get_hash_code(const unsigned long long shape)
882{
883 unsigned long long h;
884 const unsigned char *p = (const unsigned char*)&shape;
885
886 h = hash_rank[0][p[0]];
887 h ^= hash_rank[1][p[1]];
888 h ^= hash_rank[2][p[2]];
889 h ^= hash_rank[3][p[3]];
890 h ^= hash_rank[4][p[4]];
891 h ^= hash_rank[5][p[5]];
892 h ^= hash_rank[6][p[6]];
893 h ^= hash_rank[7][p[7]];
894 h ^= hash_rank[8][p[8]];
895
896 return h;
897}
898
902typedef struct {
903 unsigned long long *item;
904 int n;
905 int size;
906} ShapeArray;
907
912static void shapearray_init(ShapeArray *array)
913{
914 array->item = NULL;
915 array->n = array->size = 0;
916}
917
922static void shapearray_delete(ShapeArray *array)
923{
924 free(array->item);
925}
926
932static bool shapearray_append(ShapeArray *array, const unsigned long long shape)
933{
934 int i;
935
936 for (i = 0; i < array->n; ++i) {
937 if (array->item[i] == shape) return false;
938 }
939
940 if (array->size == array->n) {
941 array->item = (unsigned long long*) realloc(array->item, (array->size += 1) * sizeof (unsigned long long));
942 if (array->item == NULL) fatal_error("Cannot re-allocate board array.\n");
943 }
944 array->item[array->n++] = shape;
945 return true;
946}
947
948
952typedef struct {
954 int size;
955 int mask;
956} ShapeHash;
957
958
964static void shapehash_init(ShapeHash *hash, int bitsize)
965{
966 int i;
967
968 hash->size = (1 << bitsize);
969 hash->mask = hash->size - 1;
970 hash->array = (ShapeArray *) malloc(hash->size * sizeof (ShapeArray));
971 if (hash->array == NULL) fatal_error("Cannot re-allocate board array.\n");
972 for (i = 0; i < hash->size; ++i) shapearray_init(hash->array + i);
973}
974
979static void shapehash_delete(ShapeHash *hash)
980{
981 int i;
982
983 for (i = 0; i < hash->size; ++i) shapearray_delete(hash->array + i);
984 free(hash->array);
985}
986
992static bool shapehash_append(ShapeHash *hash, const Board *b)
993{
994 unsigned long long u;
995
996 u = shape_unique(b->player | b->opponent);
997 return shapearray_append(hash->array + (shape_get_hash_code(u) & hash->mask), u);
998}
999
1007static unsigned long long count_shape(ShapeHash *hash, BoardCache *cache, const Board *board, const int depth)
1008{
1009 unsigned long long nodes = 0;
1010 unsigned long long moves;
1011 int x;
1012 Board next[1];
1013
1014 if (boardcache_undone(cache, board)) {
1015 if (depth == 0) return shapehash_append(hash, board);
1016 moves = get_moves(board->player, board->opponent);
1017
1018 if (moves) {
1019 foreach_bit (x, moves) {
1020 board_next(board, x, next);
1021 nodes += count_shape(hash, cache, next, depth - 1);
1022 }
1023 } else {
1024 board_next(board, PASS, next);
1025 if (can_move(board->player, board->opponent)) {
1026 nodes += count_shape(hash, cache, next, depth);
1027 }
1028 }
1029 boardcache_append(cache, board);
1030 }
1031
1032 return nodes;
1033}
1034
1042static unsigned long long count_shape_6x6(ShapeHash *hash, BoardCache *cache, const Board *board, const int depth)
1043{
1044 unsigned long long nodes = 0;
1045 unsigned long long moves;
1046 int x;
1047 Board next[1];
1048
1049 if (boardcache_undone(cache, board)) {
1050 if (depth == 0) return shapehash_append(hash, board);
1051 moves = get_moves_6x6(board->player, board->opponent);
1052
1053 if (moves) {
1054 foreach_bit (x, moves) {
1055 board_next(board, x, next);
1056 nodes += count_shape_6x6(hash, cache, next, depth - 1);
1057 }
1058 } else {
1059 board_next(board, PASS, next);
1060 if (can_move_6x6(board->player, board->opponent)) {
1061 nodes += count_shape_6x6(hash, cache, next, depth);
1062 }
1063 }
1064 boardcache_append(cache, board);
1065 }
1066
1067 return nodes;
1068}
1069
1070
1077void count_shapes(const Board *board, const int depth, const int size)
1078{
1079 int i;
1080 unsigned long long n, c;
1081 long long t;
1082 ShapeHash hash;
1083 BoardCache cache;
1084
1085
1086 board_print(board, BLACK, stdout);
1087 puts("\n discs nodes total time speed");
1088 puts("----------------------------------------------------------");
1089 c = 0;
1090 for (i = 0; i <= depth; ++i) {
1093 t = -cpu_clock();
1094 if (size == 6) c += (n = count_shape_6x6(&hash, &cache, board, i));
1095 else c += (n = count_shape(&hash, &cache, board, i));
1096 t += cpu_clock();
1097 printf(" %2d, %12llu, %12llu, ", i + 4, n, c);
1098 time_print(t, true, stdout); printf(", ");
1099 print_scientific(c / (0.001 * t + 0.001), "N/s\n", stdout);
1100 shapehash_delete(&hash);
1101 boardcache_delete(&cache);
1102 }
1103 puts("----------------------------------------------------------");
1104}
1105
1106
1107
1115bool seek_position(const Board *target, const Board *board, Line *line) {
1116 const unsigned long long mask = target->opponent | target->player;
1117 unsigned long long moves;
1118 int x;
1119 Board next[1];
1120
1121 if (board_equal(board, target)) return true;
1122
1123 moves = get_moves(board->player, board->opponent);
1124 if (moves) {
1125 moves &= mask;
1126 foreach_bit (x, moves) {
1127 line_push(line, x);
1128 board_next(board, x, next);
1129 if (seek_position(target, next, line)) return true;
1130 line_pop(line);
1131 }
1132 } else {
1133 board_next(board, PASS, next);
1134 if (can_move(next->player, next->opponent)) {
1135 if (seek_position(target, next, line)) return true;
1136 }
1137 }
1138
1139 return false;
1140}
1141
DLL_API int bit_count(unsigned long long b)
Count the number of bits set to one in an unsigned long long.
Definition bit.c:72
unsigned long long transpose(unsigned long long b)
Transpose the unsigned long long (symetry % A1-H8 diagonal).
Definition bit.c:345
unsigned long long horizontal_mirror(unsigned long long b)
Mirror the unsigned long long (exchange the line 1 - 8, 2 - 7, 3 - 6 & 4 - 5).
Definition bit.c:377
unsigned long long vertical_mirror(unsigned long long b)
Mirror the unsigned long long (exchange the lines A - H, B - G, C - F & D - E.).
Definition bit.c:364
#define foreach_bit(i, b)
Definition bit.h:39
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
int board_count_empties(const Board *board)
Check if the game is over.
Definition board.c:1216
unsigned long long get_moves_6x6(const unsigned long long P, const unsigned long long O)
Get legal moves on a 6x6 board.
Definition board.c:779
int board_compare(const Board *b1, const Board *b2)
Compare two board.
Definition board.c:319
int board_unique(const Board *board, Board *unique)
unique board
Definition board.c:379
int board_get_square_color(const Board *board, const int x)
Get square color.
Definition board.c:1168
int get_mobility(const unsigned long long P, const unsigned long long O)
Count legal moves.
Definition board.c:833
bool can_move_6x6(const unsigned long long P, const unsigned long long O)
Check if a player can move.
Definition board.c:814
bool board_equal(const Board *b1, const Board *b2)
Compare two board for equality.
Definition board.c:335
DLL_API unsigned long long get_moves(const unsigned long long P, const unsigned long long O)
Get legal moves.
Definition board.c:621
DLL_API bool can_move(const unsigned long long P, const unsigned long long O)
Check if a player can move.
Definition board.c:797
unsigned long long board_next(const Board *board, const int x, Board *next)
Compute a board resulting of a move played on a previous board.
Definition board.c:517
@ PASS
Definition const.h:37
@ A1
Definition const.h:29
@ H8
Definition const.h:36
@ BLACK
Definition const.h:42
unsigned long long hash_rank[16][256]
Definition hash-lock-free.c:41
void line_push(Line *line, const int x)
Add a move to the sequence.
Definition move.c:561
void move_print(const int x, const int player, FILE *f)
Print out a move.
Definition move.c:110
void line_pop(Line *line)
Remove the last move from a sequence.
Definition move.c:578
Options options
Definition options.c:22
static void boardcache_delete(BoardCache *hash)
Free the hash table.
Definition perft.c:654
static void gamehash_store(GameHashTable *hash, const Board *b, const int depth, const GameStatistics *stats)
Store a game position.
Definition perft.c:368
static unsigned long long count_position(PositionHash *hash, BoardCache *cache, const Board *board, const int depth)
Recursively count positions.
Definition perft.c:757
void quick_count_games(const Board *board, const int depth, const int size)
Count games.
Definition perft.c:521
void game_statistics_cumulate(GameStatistics *global, const GameStatistics *local)
Accumulate statistics: add local data to global ones.
Definition perft.c:44
unsigned long long shape_unique(unsigned long long shape)
unique shape.
Definition perft.c:858
void estimate_games(const Board *board, const long long n)
Move estimate games.
Definition perft.c:177
static void estimate_game(const Board *board, const int depth, Random *r, double *n)
Estimate move counts from a single game.
Definition perft.c:142
const GameStatistics GAME_STATISTICS_INIT
Definition perft.c:37
void positionhash_delete(PositionHash *hash)
Free the hash table.
Definition perft.c:724
static void compact_board(const Board *b, CBoard *c)
Definition perft.c:563
bool seek_position(const Board *target, const Board *board, Line *line)
seek a game that reach to a position
Definition perft.c:1115
static bool boardcache_undone(BoardCache *hash, const Board *b)
Append a shape to the hash table.
Definition perft.c:664
static unsigned long long count_shape_6x6(ShapeHash *hash, BoardCache *cache, const Board *board, const int depth)
Recursively count shapes.
Definition perft.c:1042
static void shapehash_delete(ShapeHash *hash)
Free the hash table.
Definition perft.c:979
static void quick_count_game_6x6(GameHashTable *hash, const Board *board, const int depth, GameStatistics *global_stats)
Count games recursively.
Definition perft.c:428
static void quick_count_game(GameHashTable *hash, const Board *board, const int depth, GameStatistics *global_stats)
Count games recursively.
Definition perft.c:475
static void boardcache_init(BoardCache *hash, int bitsize)
Initialisation of the hash table.
Definition perft.c:639
void seek_highest_mobility(const Board *board, const unsigned long long t)
Move estimate games.
Definition perft.c:290
struct PosArray PosArray
struct CBoard CBoard
static unsigned long long count_position_6x6(PositionHash *hash, BoardCache *cache, const Board *board, const int depth)
Recursively count positions.
Definition perft.c:790
static bool shapehash_append(ShapeHash *hash, const Board *b)
Append a shape to the hash table.
Definition perft.c:992
static void gamehash_init(GameHashTable *hash, int bitsize)
Hash table initialisation.
Definition perft.c:338
static void boardcache_append(BoardCache *hash, const Board *b)
Definition perft.c:682
static void positionarray_init(PosArray *array)
array initialisation.
Definition perft.c:589
static unsigned long long count_shape(ShapeHash *hash, BoardCache *cache, const Board *board, const int depth)
Recursively count shapes.
Definition perft.c:1007
bool positionhash_append(PositionHash *hash, const Board *b)
Append a position to the hash table.
Definition perft.c:738
static void shapehash_init(ShapeHash *hash, int bitsize)
Initialisation of the hash table.
Definition perft.c:964
static bool shapearray_append(ShapeArray *array, const unsigned long long shape)
Append a shape into the array.
Definition perft.c:932
static bool positionarray_append(PosArray *array, const CBoard *b)
Append a position.
Definition perft.c:610
static bool gamehash_fail(GameHashTable *hash, const Board *b, const int depth, GameStatistics *stats)
Seek for a position in the hash table.
Definition perft.c:395
void count_shapes(const Board *board, const int depth, const int size)
Count shapes.
Definition perft.c:1077
static void shapearray_init(ShapeArray *array)
array initialisation.
Definition perft.c:912
static void test_mobility(const Board *board, const int ply, Random *r, int *move, int *max_mobility, int *max_empties, const unsigned long long n)
Estimate move counts from a single game.
Definition perft.c:239
static void shapearray_delete(ShapeArray *array)
array supression.
Definition perft.c:922
void count_positions(const Board *board, const int depth, const int size)
Count positions.
Definition perft.c:822
unsigned long long shape_get_hash_code(const unsigned long long shape)
Compute a hash code.
Definition perft.c:881
void count_games(const Board *board, const int depth)
Move generator performance test.
Definition perft.c:107
const GameHash GAME_HASH_INIT
Definition perft.c:321
static void count_game(const Board *board, const int depth, GameStatistics *global_stats)
Move generator performance test function.
Definition perft.c:63
static void gamehash_delete(GameHashTable *hash)
Hash table resource freeing.
Definition perft.c:355
void positionhash_init(PositionHash *hash, int bitsize)
Initialisation of the hash table.
Definition perft.c:709
static void positionarray_delete(PosArray *array)
array supression.
Definition perft.c:599
Move generator test header file.
Definition perft.c:628
int size
Definition perft.c:630
int mask
Definition perft.c:631
Board * array
Definition perft.c:629
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
Definition perft.c:558
unsigned char x[13]
Definition perft.c:559
Definition perft.c:324
unsigned long long n_tries
Definition perft.c:328
GameHash * array
Definition perft.c:325
unsigned long long n_hits
Definition perft.c:329
int mask
Definition perft.c:327
int size
Definition perft.c:326
Definition perft.c:314
GameStatistics stats
Definition perft.c:316
Board board
Definition perft.c:315
int depth
Definition perft.c:317
Definition perft.c:26
unsigned long long n_passes
Definition perft.c:31
unsigned long long n_losses
Definition perft.c:29
unsigned int min_mobility
Definition perft.c:32
unsigned long long n_moves
Definition perft.c:27
unsigned long long n_wins
Definition perft.c:30
unsigned long long n_draws
Definition perft.c:28
unsigned int max_mobility
Definition perft.c:33
Definition move.h:35
int hash_table_size
Definition options.h:25
Definition perft.c:579
CBoard * item
Definition perft.c:580
int size
Definition perft.c:582
int n
Definition perft.c:581
Definition perft.h:27
int mask
Definition perft.h:30
struct PosArray * array
Definition perft.h:28
int size
Definition perft.h:29
Definition util.h:87
Definition perft.c:902
int n
Definition perft.c:904
int size
Definition perft.c:905
unsigned long long * item
Definition perft.c:903
Definition perft.c:952
int size
Definition perft.c:954
ShapeArray * array
Definition perft.c:953
int mask
Definition perft.c:955
void time_print(long long t, bool justified, FILE *f)
Print time as "D:HH:MM:SS.CC".
Definition util.c:131
void print_scientific(double v, const char *unit, FILE *f)
Print a value with a unit.
Definition util.c:250
unsigned long long random_get(Random *random)
Pseudo-random number generator.
Definition util.c:1043
void random_seed(Random *random, const unsigned long long seed)
Pseudo-random number seed.
Definition util.c:1062
Miscellaneous utilities header.
long long real_clock(void)
long long cpu_clock(void)
#define fatal_error(...)
Display an error message as "FATAL_ERROR : file name : function name : line number : ....
Definition util.h:349