#include "table_search.h" TableEntry *transposition_table; static int hashes[WHOLE_BOARD_SIZE][MAX_PIECES]; inline int table_index(int hash) { return hash % TABLE_SIZE; } // calculate zobrist hashing inline int table_hash(int thisside[], int otherside[]) { int hash = 0; for (int i = 0; i < WHOLE_BOARD_SIZE; ++i) { int value; // first half of board if (i < BOARD_SIZE) { value = thisside[i]; } else { value = otherside[i % BOARD_SIZE]; } assert(WHOLE_BOARD_SIZE > i); assert(MAX_PIECES > value); hash ^= hashes[i][value]; } return hash; } inline void print_entry(TableEntry entry) { fprintf(stdout, "TableEntry { hash: %i, depth: %i, evaluated: %i, best_move: %i }\n", entry.hash, entry.depth, entry.evaluated, entry.best_move); } inline void init_hashes() { transposition_table = calloc(TABLE_SIZE, sizeof(TableEntry)); // init hashes srand((unsigned int)time(NULL)); for (int i = 0; i < WHOLE_BOARD_SIZE; ++i) { for (int j = 0; j < MAX_PIECES; ++j) { hashes[i][j] = rand(); } } } int value1(int side[]) { int v = side[houses]; if (v > 24) /* win */ return 100; if (v == 24) /* draw or better */ return 50; return v; } int value(int thisside[], int otherside[]) { return value1(thisside) - value1(otherside); } int alpha_beta_bestmove(int depth, int thisside[], int otherside[], int *vp) { // initialize hashes for the table init_hashes(); int ts1[BOARD_SIZE], os1[BOARD_SIZE]; int best_move = -1; int alpha = MIN_INFINITY; int current_value; for (int move = 0; move < houses; move++) { memcpy(ts1, thisside, BOARD_ARRAY_SIZE); memcpy(os1, otherside, BOARD_ARRAY_SIZE); if (plyfull(move, ts1, os1)) { current_value = value(ts1, os1); if (depth > 0 && current_value <= 50 && current_value >= -50) { current_value = -helper_alpha_beta_search(depth - 1, -MAX_INFINITY, -alpha, os1, ts1); } if (current_value > alpha) { best_move = move; alpha = current_value; } } } *vp = alpha; return best_move; } int helper_alpha_beta_search(int depth, int alpha, int beta, int thisside[], int otherside[]) { int ts1[BOARD_SIZE], os1[BOARD_SIZE]; for (int move = 0; move < houses; move++) { memcpy(ts1, thisside, BOARD_ARRAY_SIZE); memcpy(os1, otherside, BOARD_ARRAY_SIZE); // has value saved in transposition_table int hash = table_hash(ts1, os1); TableEntry entry = transposition_table[table_index(hash)]; if (entry.hash != 0 && hash == entry.hash && entry.depth >= depth) { //print_entry(entry); return entry.evaluated; } else if (plyfull(move, ts1, os1)) { int current_value = value(ts1, os1); if (depth > 0 && current_value <= 50 && current_value >= -50) { current_value = -helper_alpha_beta_search(depth - 1, -beta, -alpha, os1, ts1); } if (current_value > alpha) { if (current_value >= beta) { // Add entry int hash2 = table_hash(os1, ts1); int index2 = table_index(hash2); TableEntry entry2 = transposition_table[index2]; if (entry2.hash == 0 || (entry2.hash != 0 && entry2.depth < depth - 1)) { TableEntry new_entry = { .hash = hash, .depth = depth - 1, .evaluated = current_value, }; transposition_table[index2] = new_entry; } return current_value; } alpha = current_value; } } } // Add entry int hash = table_hash(thisside, otherside); int index = table_index(hash); TableEntry entry = transposition_table[index]; if (entry.hash == 0 || (entry.hash != 0 && entry.depth < depth)) { TableEntry new_entry = { .hash = hash, .depth = depth, .evaluated = alpha, }; transposition_table[index] = new_entry; } return alpha; }