My Project
move.c
Go to the documentation of this file.
1
11#include "move.h"
12
13#include "bit.h"
14#include "board.h"
15#include "hash.h"
16#include "search.h"
17#include "settings.h"
18#include "stats.h"
19
20#include <limits.h>
21#include <assert.h>
22#include <ctype.h>
23#include <string.h>
24
25const Move MOVE_INIT = {0, NOMOVE, -SCORE_INF, 0, NULL};
26const Move MOVE_PASS = {0, PASS, -SCORE_INF, 0, NULL};
27
28const int SQUARE_VALUE[] = {
29 // JCW's score:
30 18, 4, 16, 12, 12, 16, 4, 18,
31 4, 2, 6, 8, 8, 6, 2, 4,
32 16, 6, 14, 10, 10, 14, 6, 16,
33 12, 8, 10, 0, 0, 10, 8, 12,
34 12, 8, 10, 0, 0, 10, 8, 12,
35 16, 6, 14, 10, 10, 14, 6, 16,
36 4, 2, 6, 8, 8, 6, 2, 4,
37 18, 4, 16, 12, 12, 16, 4, 18
38};
39
47int symetry(int x, const int sym)
48{
49 if (A1 <= x && x <= H8) {
50 if (sym & 1) {
51 x = ((x & 070) | (7 - (x & 7)));
52 }
53 if (sym & 2) {
54 x = ((070 - (x & 070)) | (x & 7));
55 }
56 if (sym & 4) {
57 x = (((x & 070) >> 3) | ((x & 7) << 3));
58 }
59 assert(A1 <= x && x <= H8);
60 }
61
62 return x;
63}
64
65
76char* move_to_string(const int x, const int player, char *s)
77{
78 if (x == NOMOVE) {
79 s[0] = '-';
80 s[1] = '-';
81 } else if (x == PASS) {
82 s[0] = 'p';
83 s[1] = 'a';
84 } else if (x >= A1 && x <= H8) {
85 s[0] = x % 8 + 'a';
86 s[1] = x / 8 + '1';
87 } else {
88 s[0] = '?';
89 s[1] = '?';
90 }
91
92 if (player == BLACK) {
93 s[0] = toupper(s[0]);
94 s[1] = toupper(s[1]);
95 }
96 s[2] = '\0';
97
98 return s;
99}
100
110void move_print(const int x, const int player, FILE *f)
111{
112 int s[2];
113
114 if (x == NOMOVE) {
115 s[0] = '-';
116 s[1] = '-';
117 } else if (x == PASS) {
118 s[0] = 'p';
119 s[1] = 's';
120 } else if (x >= A1 && x <= H8) {
121 s[0] = x % 8 + 'a';
122 s[1] = x / 8 + '1';
123 } else {
124 s[0] = '?';
125 s[1] = '?';
126 }
127
128 if (player == BLACK) {
129 s[0] = toupper(s[0]);
130 s[1] = toupper(s[1]);
131 }
132 fputc(s[0], f);
133 fputc(s[1], f);
134}
135
136
137
138
148bool move_wipeout(const Move *move, const Board *board)
149{
150 return move->flipped == board->opponent;
151}
152
153#ifdef TUNE_EDAX
154static int w_hash = 1 << 15;
155static int w_eval = 1 << 15;
156static int w_mobility = 1 << 15;
157static int w_corner_stability = 1 << 11;
158static int w_edge_stability = 1 << 11;
159static int w_potential_mobility = 1 << 5;
160static int w_low_parity = 1 << 3;
161static int w_mid_parity = 1 << 2;
162static int w_high_parity = 1 << 1;
163#endif
164
165
186static void move_evaluate(Move *move, Search *search, const HashData *hash_data, const int sort_alpha, const int sort_depth)
187{
188#ifndef TUNE_EDAX
189 const int w_hash = 1 << 15;
190 const int w_eval = 1 << 15;
191 const int w_mobility = 1 << 15;
192 const int w_corner_stability = 1 << 11;
193 const int w_edge_stability = 1 << 11;
194 const int w_potential_mobility = 1 << 5;
195 const int w_low_parity = 1 << 3;
196 const int w_mid_parity = 1 << 2;
197 const int w_high_parity = 1 << 1;
198#endif
199
200 Board *board = search->board;
201 HashData dummy[1];
202
203 if (move_wipeout(move, board)) move->score = (1 << 30);
204 else if (move->x == hash_data->move[0]) move->score = (1 << 29);
205 else if (move->x == hash_data->move[1]) move->score = (1 << 28);
206 else {
207
208 move->score = SQUARE_VALUE[move->x]; // square type
209 if (search->n_empties < 12 && search->parity & QUADRANT_ID[move->x]) move->score += w_low_parity; // parity
210 else if (search->n_empties < 21 && search->parity & QUADRANT_ID[move->x]) move->score += w_mid_parity; // parity
211 else if (search->n_empties < 30 && search->parity & QUADRANT_ID[move->x]) move->score += w_high_parity; // parity
212
213 if (sort_depth < 0) {
214 board_update(board, move);
216 move->score += (36 - get_potential_mobility(board->player, board->opponent)) * w_potential_mobility; // potential mobility
217 move->score += get_corner_stability(board->opponent) * w_corner_stability; // corner stability
218 move->score += (36 - get_weighted_mobility(board->player, board->opponent)) * w_mobility; // real mobility
219 board_restore(board, move);
220 } else {
221 int selectivity = search->selectivity;
222 search->selectivity = NO_SELECTIVITY;
223 search_update_midgame(search, move);
225 move->score += (36 - get_potential_mobility(board->player, board->opponent)) * w_potential_mobility; // potential mobility
226 move->score += get_edge_stability(board->opponent, board->player) * w_edge_stability; // edge stability
227 move->score += (36 - get_weighted_mobility(board->player, board->opponent)) * w_mobility; // real mobility
228 switch(sort_depth) {
229 case 0:
230 move->score += ((SCORE_MAX - search_eval_0(search)) >> 2) * w_eval; // 1 level score bonus
231 break;
232 case 1:
233 move->score += ((SCORE_MAX - search_eval_1(search, SCORE_MIN, -sort_alpha)) >> 1) * w_eval; // 2 level score bonus
234 break;
235 case 2:
236 move->score += ((SCORE_MAX - search_eval_2(search, SCORE_MIN, -sort_alpha)) >> 1) * w_eval; // 3 level score bonus
237 break;
238 default:
239 if (hash_get(search->hash_table, search->board, board_get_hash_code(search->board), dummy)) move->score += w_hash; // bonus if the position leads to a position stored in the hash-table
240 move->score += ((SCORE_MAX - PVS_shallow(search, SCORE_MIN, -sort_alpha, sort_depth))) * w_eval; // > 3 level bonus
241 break;
242 }
243 search_restore_midgame(search, move);
244 search->selectivity = selectivity;
245 }
246 }
247}
248
249#ifdef TUNE_EDAX
250#include "solver.h"
251
252void tune_move_evaluate(Search *search, const char *filename, const char *w_name)
253{
254 int best_w;
255 unsigned long long best_n_nodes;
256 unsigned long long n_nodes, t;
257 int i, *w;
258
259 if (strcmp(w_name, "w_eval") == 0) w = &w_eval;
260 else if (strcmp(w_name, "w_mobility") == 0) w = &w_mobility;
261 else if (strcmp(w_name, "w_corner_stability") == 0) w = &w_corner_stability;
262 else if (strcmp(w_name, "w_edge_stability") == 0) w = &w_edge_stability;
263 else if (strcmp(w_name, "w_potential_mobility") == 0) w = &w_potential_mobility;
264 else if (strcmp(w_name, "w_low_parity") == 0) w = &w_low_parity;
265 else if (strcmp(w_name, "w_mid_parity") == 0) w = &w_mid_parity;
266 else if (strcmp(w_name, "w_high_parity") == 0) w = &w_high_parity;
267 else {
268 warn("unknown parameter %s\n", w_name);
269 return;
270 }
271
272 best_n_nodes = ULLONG_MAX;
273 best_w = *w;
274
275 for (i = -1; i <= 20; ++i) {
276 *w = (i >= 0 ? 1 << i : 0);
277 t = -time_clock();
278 n_nodes = solver(search, filename);
279 t += time_clock();
280 printf("%s %d : nodes %llu : time %.3f\n", w_name, *w, n_nodes, 0.001 * t);
281 if (n_nodes < best_n_nodes) {
282 best_n_nodes = n_nodes;
283 best_w = *w;
284 }
285 }
286 printf("Best %s %d : %llu\n", w_name, best_w, best_n_nodes);
287 *w = best_w;
288}
289#endif
290
298int movelist_get_moves(MoveList *movelist, const Board *board)
299{
300 Move *previous = movelist->move;
301 Move *move = movelist->move + 1;
302 unsigned long long moves = get_moves(board->player, board->opponent);
303 int x;
304
305 foreach_bit(x, moves) {
306 board_get_move(board, x, move);
307 move->score = -SCORE_INF;
308 previous = previous->next = move;
309 ++move;
310 }
311 previous->next = NULL;
312 movelist->n_moves = move - movelist->move - 1;
313
314 assert(movelist->n_moves == get_mobility(board->player, board->opponent));
315
316 return movelist->n_moves;
317}
318
319
320
330void movelist_print(const MoveList *movelist, const int player, FILE *f)
331{
332 Move *iter;
333
334 for (iter = movelist->move->next; iter != NULL; iter = iter->next) {
335 move_print(iter->x, player, f);
336 fprintf(f, "[%d] ", iter->score);
337 }
338}
339
346Move* move_next_best(Move *previous_best)
347{
348 if (previous_best->next) {
349 Move *move, *best;
350 best = previous_best;
351 for (move = best->next; move->next != NULL; move = move->next) {
352 if (move->next->score > best->next->score) {
353 best = move;
354 }
355 }
356 if (previous_best != best) {
357 move = best->next;
358 best->next = move->next;
359 move->next = previous_best->next;
360 previous_best->next = move;
361 }
362 }
363
364 return previous_best->next;
365}
366
374{
375 if (previous_best->next) {
376 Move *move, *best;
377 best = previous_best;
378 for (move = best->next; move->next != NULL; move = move->next) {
379 if (move->next->cost > best->next->cost) {
380 best = move;
381 }
382 }
383 if (previous_best != best) {
384 move = best->next;
385 best->next = move->next;
386 move->next = previous_best->next;
387 previous_best->next = move;
388 }
389 }
390
391 return previous_best->next;
392}
393
401{
402 return move->next;
403}
404
412{
413 return move_next_best(movelist->move);
414}
415
423{
424 return move_next(movelist->move);
425}
426
436void movelist_evaluate(MoveList *movelist, Search *search, const HashData *hash_data, const int alpha, const int depth)
437{
438 int sort_depth, min_depth;
439 int sort_alpha;
440 Move *move;
441
442 min_depth = 9;
443 if (search->n_empties <= 27) min_depth += (30 - search->n_empties) / 3;
444 if (depth >= min_depth) {
445 sort_depth = (depth - 15) / 3;
446 if (hash_data && hash_data->upper < alpha) sort_depth -= 2;
447 if (search->n_empties >= 27) ++sort_depth;
448 if (sort_depth < 0) sort_depth = 0; else if (sort_depth > 6) sort_depth = 6;
449 } else {
450 sort_depth = -1;
451 }
452
453 sort_alpha = MAX(SCORE_MIN, alpha - SORT_ALPHA_DELTA);
454 foreach_move (move, movelist) {
455 move_evaluate(move, search, hash_data, sort_alpha, sort_depth);
456 }
457}
458
468Move* movelist_sort_bestmove(MoveList *movelist, const int move)
469{
470 Move *iter, *previous;
471
472 for (iter = (previous = movelist->move)->next; iter != NULL; iter = (previous = iter)->next) {
473 if (iter->x == move) {
474 previous->next = iter->next;
475 iter->next = movelist->move->next;
476 movelist->move->next = iter;
477 break;
478 }
479 }
480 return previous;
481}
482
489void movelist_sort_cost(MoveList *movelist, const HashData *hash_data)
490{
491 Move *iter;
492
493
494 foreach_move(iter, movelist) {
495 if (iter->x == hash_data->move[0]) iter->cost = INT_MAX;
496 else if (iter->x == hash_data->move[1]) iter->cost = INT_MAX - 1;
497 }
498 for (iter = move_next_most_expensive(movelist->move); iter; iter = move_next_most_expensive(iter));
499}
500
505void movelist_sort(MoveList *movelist)
506{
507 Move *move;
508 foreach_best_move(move, movelist) ;
509}
510
516Move* movelist_exclude(MoveList *movelist, const int move)
517{
518 Move *iter, *previous;
519
520 for (iter = (previous = movelist->move)->next; iter != NULL; iter = (previous = iter)->next) {
521 if (iter->x == move) {
522 previous->next = iter->next;
523 break;
524 }
525 }
526 if (iter) --movelist->n_moves;
527
528 return iter;
529}
530
537bool movelist_is_empty(const MoveList *movelist)
538{
539 return movelist->n_moves == 0;
540}
541
542
549void line_init(Line *line, const int player)
550{
551 line->n_moves = 0;
552 line->color = player;
553}
554
561void line_push(Line* line, const int x)
562{
563 int i;
564
565 assert(line->n_moves < GAME_SIZE);
566
567 for (i = 0; i < line->n_moves; ++i) {
568 assert(line->move[i] != x || x == PASS);
569 }
570 line->move[line->n_moves++] = (char) x;
571}
572
578void line_pop(Line* line)
579{
580 assert(line->n_moves > 0);
581 --line->n_moves;
582}
583
591void line_copy(Line *dest, const Line *src, const int from)
592{
593 int i;
594
595 for (i = from; i < src->n_moves; ++i) { // todo: replace by memcpy ?
596 dest->move[i] = src->move[i];
597 }
598 dest->n_moves = src->n_moves;
599 dest->color = src->color;
600}
601
610void line_print(const Line *line, int width, const char *separator, FILE *f)
611{
612 int i;
613 int player = line->color;
614 int w = 2 + (separator ? strlen(separator) : 0);
615 int len = abs(width);
616
617 for (i = 0; i < line->n_moves && len > w; ++i, len -= w) {
618 player = !player;
619 if (separator && i) fputs(separator, f);
620 move_print(line->move[i], player, f);
621 }
622 for (len = MIN(len, width); len > w; len -= w) {
623 fputc(' ', f);fputc(' ', f); if (separator) fputs(separator, f);
624 }
625}
626
635char* line_to_string(const Line *line, int n, const char *separator, char *string)
636{
637 int i;
638 int player = line->color;
639 int w = 2 + (separator ? strlen(separator) : 0);
640
641 for (i = 0; i < line->n_moves && i < n; ++i) {
642 move_to_string(line->move[i], player, string + w * i);
643 player = !player;
644 if (separator) strcpy(string + w * i + 2, separator);
645 }
646 string[w * i] = '\0';
647 return string;
648}
649
653typedef struct {
655 int x;
656} MBoard;
657
661typedef struct MoveArray {
663 int n;
664 int size;
666
671static void movearray_init(MoveArray *array)
672{
673 array->item = NULL;
674 array->n = array->size = 0;
675}
676
681static void movearray_delete(MoveArray *array)
682{
683 free(array->item);
684}
685
693static bool movearray_append(MoveArray *array, const Board *b, const int x)
694{
695 int i;
696 for (i = 0; i < array->n; ++i) {
697 if (array->item[i].x == x && board_equal(b, &(array->item[i].board))) return false;
698 }
699
700 if (array->size < array->n + 1) {
701 array->item = (MBoard*) realloc(array->item, (array->size = (array->size + 1)) * sizeof (MBoard));
702 if (array->item == NULL) fatal_error("Cannot re-allocate board array.\n");
703 }
704 array->item[array->n].board = *b;
705 array->item[array->n].x = x;
706 ++array->n;
707 return true;
708}
709
715void movehash_init(MoveHash *hash, int bitsize)
716{
717 int i;
718
719 hash->size = (1 << bitsize);
720 hash->mask = hash->size - 1;
721 hash->array = (MoveArray*) malloc(hash->size * sizeof (MoveArray));
722 if (hash->array == NULL) fatal_error("Cannot re-allocate board array.\n");
723 for (i = 0; i < hash->size; ++i) movearray_init(hash->array + i);
724}
725
731{
732 int i;
733
734 for (i = 0; i < hash->size; ++i) movearray_delete(hash->array + i);
735 free(hash->array);
736}
737
745bool movehash_append(MoveHash *hash, const Board *b, const int x)
746{
747 Board u;
748 int y;
749 unsigned long long h;
750
751 y = symetry(x, board_unique(b, &u));
752 h = board_get_hash_code(&u);
753 return movearray_append(hash->array + (h & hash->mask), &u, y);
754}
755
#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_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 get_potential_mobility(const unsigned long long P, const unsigned long long O)
Get potential mobility.
Definition board.c:882
unsigned long long board_get_move(const Board *board, const int x, Move *move)
Compute a move.
Definition board.c:438
int get_corner_stability(const unsigned long long P)
Estimate corner stability.
Definition board.c:1122
int board_unique(const Board *board, Board *unique)
unique board
Definition board.c:379
int get_mobility(const unsigned long long P, const unsigned long long O)
Count legal moves.
Definition board.c:833
int get_edge_stability(const unsigned long long P, const unsigned long long O)
Estimate the stability of edges.
Definition board.c:1106
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
int get_weighted_mobility(const unsigned long long P, const unsigned long long O)
Definition board.c:838
#define SCORE_MAX
Definition const.h:58
#define SCORE_INF
Definition const.h:52
#define GAME_SIZE
Definition const.h:25
@ PASS
Definition const.h:37
@ NOMOVE
Definition const.h:37
@ A1
Definition const.h:29
@ H8
Definition const.h:36
@ BLACK
Definition const.h:42
#define SCORE_MIN
Definition const.h:55
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
int search_eval_2(Search *search, int alpha, const int beta)
Evaluate a position at depth 2.
Definition midgame.c:147
int search_eval_0(Search *search)
evaluate a midgame position with the evaluation function.
Definition midgame.c:32
int PVS_shallow(Search *search, int alpha, int beta, int depth)
Evaluate a midgame position at shallow depth.
Definition midgame.c:381
int search_eval_1(Search *search, const int alpha, int beta)
Evaluate a position at depth 1.
Definition midgame.c:74
Move * movelist_best(MoveList *movelist)
Return the best move of the list.
Definition move.c:411
void line_print(const Line *line, int width, const char *separator, FILE *f)
Print a move sequence.
Definition move.c:610
Move * move_next_most_expensive(Move *previous_best)
Return the next best move from the list.
Definition move.c:373
const int SQUARE_VALUE[]
Definition move.c:28
bool movelist_is_empty(const MoveList *movelist)
Check if the list is empty.
Definition move.c:537
void line_push(Line *line, const int x)
Add a move to the sequence.
Definition move.c:561
void movehash_delete(MoveHash *hash)
Free the hash table.
Definition move.c:730
bool move_wipeout(const Move *move, const Board *board)
Check if a move wins 64-0.
Definition move.c:148
void movehash_init(MoveHash *hash, int bitsize)
Initialisation of the hash table.
Definition move.c:715
void movelist_print(const MoveList *movelist, const int player, FILE *f)
Print out a movelist.
Definition move.c:330
void move_print(const int x, const int player, FILE *f)
Print out a move.
Definition move.c:110
const Move MOVE_PASS
Definition move.c:26
void movelist_sort(MoveList *movelist)
Sort all moves.
Definition move.c:505
struct MoveArray MoveArray
static void move_evaluate(Move *move, Search *search, const HashData *hash_data, const int sort_alpha, const int sort_depth)
Evaluate a list of move.
Definition move.c:186
Move * movelist_first(MoveList *movelist)
Return the first move of the list.
Definition move.c:422
bool movehash_append(MoveHash *hash, const Board *b, const int x)
Append a position to the hash table.
Definition move.c:745
static void movearray_delete(MoveArray *array)
array supression.
Definition move.c:681
Move * move_next(Move *move)
Return the next move from the list.
Definition move.c:400
static bool movearray_append(MoveArray *array, const Board *b, const int x)
Append a position.
Definition move.c:693
void line_init(Line *line, const int player)
Initialize a sequence of moves.
Definition move.c:549
Move * move_next_best(Move *previous_best)
Return the next best move from the list.
Definition move.c:346
void movelist_sort_cost(MoveList *movelist, const HashData *hash_data)
Sort all moves except the first, based on move cost & hash_table storage.
Definition move.c:489
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
void line_pop(Line *line)
Remove the last move from a sequence.
Definition move.c:578
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
Move * movelist_exclude(MoveList *movelist, const int move)
Exclude a move.
Definition move.c:516
const Move MOVE_INIT
Definition move.c:25
char * move_to_string(const int x, const int player, char *s)
Print out a move.
Definition move.c:76
int symetry(int x, const int sym)
Get a symetric square coordinate.
Definition move.c:47
static void movearray_init(MoveArray *array)
array initialisation.
Definition move.c:671
void line_copy(Line *dest, const Line *src, const int from)
Copy part of a sequence to another sequence.
Definition move.c:591
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
#define foreach_best_move(iter, movelist)
Definition move.h:82
void tune_move_evaluate(struct Search *, const char *, const char *)
const int NO_SELECTIVITY
Definition search.c:94
const int QUADRANT_ID[]
Definition search.c:81
void search_restore_midgame(Search *search, const Move *move)
Restore the search state as before a move.
Definition search.c:964
void search_update_midgame(Search *search, const Move *move)
Update the search state after a move.
Definition search.c:942
#define SORT_ALPHA_DELTA
Definition settings.h:98
Statistics header.
#define SEARCH_UPDATE_ALL_NODES()
Definition stats.h:54
#define SEARCH_UPDATE_INTERNAL_NODES()
Definition stats.h:40
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
Definition hash.h:24
unsigned char move[2]
Definition hash.h:31
signed char upper
Definition hash.h:30
Definition move.h:35
int n_moves
Definition move.h:37
char move[GAME_SIZE]
Definition move.h:36
int color
Definition move.h:38
Definition move.c:653
Board board
Definition move.c:654
int x
Definition move.c:655
Definition move.c:661
int n
Definition move.c:663
int size
Definition move.c:664
MBoard * item
Definition move.c:662
Definition move.h:93
int mask
Definition move.h:96
int size
Definition move.h:95
struct MoveArray * array
Definition move.h:94
Definition move.h:29
int n_moves
Definition move.h:31
Move move[MAX_MOVE+2]
Definition move.h:30
Definition move.h:20
unsigned int cost
Definition move.h:24
int score
Definition move.h:23
struct Move * next
Definition move.h:25
unsigned long long flipped
Definition move.h:21
int x
Definition move.h:22
Definition search.h:95
unsigned int parity
Definition search.h:120
int n_empties
Definition search.h:99
HashTable hash_table[1]
Definition search.h:103
int selectivity
Definition search.h:118
Board board[1]
Definition search.h:96
long long(* time_clock)(void)
Time clock.
Definition util.c:122
#define MIN(a, b)
Definition util.h:101
#define fatal_error(...)
Display an error message as "FATAL_ERROR : file name : function name : line number : ....
Definition util.h:349
#define warn(...)
Display a warning message as "WARNING : ... ".
Definition util.h:373
#define MAX(a, b)
Definition util.h:98