Skip to content

Commit

Permalink
Optimize search efficiency with transposition table
Browse files Browse the repository at this point in the history
Introduce the utilization of Zobrist hashing to implement a
transposition table, enhancing the search efficiency of the algorithm.
The transposition table serves to prevent redundant searches of
identical game states, thereby optimizing the overall search process.

Introduce the utilization of Zobrist hashing to implement a
transposition table, enhancing the search efficiency of the algorithm.
The transposition table serves to prevent redundant searches of
identical game states, thereby optimizing the overall search process.

Experimental results for the first moves at positions a1 and b2
demonstrate a notable reduction in search count:

+----+---------+---------+
|    | Before  | After   |
+----+---------+---------+
| a1 | 13464   | 10479   |
| b2 | 16531   |  9419   |
+----+---------+---------+
  • Loading branch information
visitorckw committed Feb 15, 2024
1 parent 15f7954 commit dab098e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
21 changes: 19 additions & 2 deletions agents/negamax.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@

#include "game.h"
#include "negamax.h"
#include "zobrist.h"

#define MAX_SEARCH_DEPTH 6

static int history_score_sum[N_GRIDS];
static int history_count[N_GRIDS];

static unsigned long long hash_value;

static int cmp_moves(const void *a, const void *b)
{
int *_a = (int *) a, *_b = (int *) b;
Expand Down Expand Up @@ -73,6 +76,9 @@ static move_t negamax(char *table, int depth, char player, int alpha, int beta)
move_t result = {get_score(table, player), -1};
return result;
}
zobrist_entry_t *entry = zobrist_get(hash_value);
if (entry)
return (move_t){.score = entry->score, .move = entry->move};

int score;
move_t best_move = {-10000, -1};
Expand All @@ -83,6 +89,7 @@ static move_t negamax(char *table, int depth, char player, int alpha, int beta)
qsort(moves, n_moves, sizeof(int), cmp_moves);
for (int i = 0; i < n_moves; i++) {
table[moves[i]] = player;
hash_value ^= zobrist_table[moves[i]][player == 'X'];
if (!i) // do a full search on the first move
score = -negamax(table, depth - 1, player == 'X' ? 'O' : 'X', -beta,
-alpha)
Expand All @@ -104,22 +111,32 @@ static move_t negamax(char *table, int depth, char player, int alpha, int beta)
best_move.move = moves[i];
}
table[moves[i]] = ' ';
hash_value ^= zobrist_table[moves[i]][player == 'X'];
if (score > alpha)
alpha = score;
if (alpha >= beta)
break;
}

free((char *) moves);
zobrist_put(hash_value, best_move.score, best_move.move);
return best_move;
}

void negamax_init()
{
zobrist_init();
hash_value = 0;
}

move_t negamax_predict(char *table, char player)
{
memset(history_score_sum, 0, sizeof(history_score_sum));
memset(history_count, 0, sizeof(history_count));
move_t result;
for (int depth = 2; depth <= MAX_SEARCH_DEPTH; depth += 2)
for (int depth = 2; depth <= MAX_SEARCH_DEPTH; depth += 2) {
result = negamax(table, depth, player, -100000, 100000);
zobrist_clear();
}
return result;
}
}
3 changes: 2 additions & 1 deletion agents/negamax.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ typedef struct {
int score, move;
} move_t;

move_t negamax_predict(char *table, char player);
void negamax_init();
move_t negamax_predict(char *table, char player);
2 changes: 2 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ int main()
char turn = 'X';
char ai = 'O';

negamax_init();

while (1) {
char win = check_win(table);
if (win == 'D') {
Expand Down

0 comments on commit dab098e

Please sign in to comment.