3

I'm currently learning to make a Gomoku ai script that uses minimax algorithm along with alpha beta pruning and other methods to improve performance. In this current state, I've implemented a transposition table into the project. The problem is, the hit rate of the table is only around 1~4%, which is quite low I suppose.

So I start by making a Zobrist hash table,

import random

BOARD_SIZE = 19

zobrist_table = [[[random.getrandbits(64) for _ in range(3)] 
                  for _ in range(BOARD_SIZE)] 
                 for _ in range(BOARD_SIZE)]

def get_initial_hash(grid):
    h = 0
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            piece = grid[r][c]
            if piece != ' ':
                h = update_hash(piece, r, c)
    return h

def update_hash(player, row, col, current_hash):
    p_idx = 1 if player == 'X' else 2
    current_hash ^= zobrist_table[row][col][p_idx]
    return current_hash

then I integrate it into the board class in the Gomoku file,

def __init__(self, grid=None):
        self.rows = ROWS
        self.cols = COLS
        self.current_hash = 0

        if grid:
            self.grid = grid
            self.current_hash = get_initial_hash(self.grid)
        else:
            self.grid = [[' ' for _ in range(self.cols)] for _ in range(self.rows)]

    def set_move(self, move, player):
        if self.grid[move.row][move.col] == ' ':
            self.grid[move.row][move.col] = player
            self.current_hash = update_hash(player, move.row, move.col, self.current_hash)
            return True
        return False

    def undo_move(self, move):
        player = self.grid[move.row][move.col]
        if player != ' ':
            self.current_hash = update_hash(player, move.row, move.col, self.current_hash)
            self.grid[move.row][move.col] = ' '

then in the pruning function, I update the hash by doing

state_key = board.current_hash
    if state_key in transposition_table:
        cached_depth, cached_score = transposition_table[state_key]
        if cached_depth >= depth:
            return cached_score

and at the end of the pruning function, I do

transposition_table[state_key] = (depth, value)

I'm not sure what I've done wrong here so please point it out if you spot any.

1 Answer 1

2

First, bug is here:

def get_initial_hash(grid):
    h = 0
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            piece = grid[r][c]
            if piece != ' ':
                update_hash(piece, r, c)
    return h

You never save the returned hash, so this function always returns 0.

It should be:

def get_initial_hash(grid):
    h = 0
    for r in range(BOARD_SIZE):
        for c in range(BOARD_SIZE):
            piece = grid[r][c]
            if piece != ' ':
                h = update_hash(piece, r, c, h)
    return h

Second, your transposition table is too simple for alpha-beta.
With pruning, a cached score is not always an exact value. Sometimes it is only a lower bound or upper bound. So storing just:

(depth, score)

can give weak results. Usually you also store a flag like exact / lower / upper.

Also, 1-4% hit rate is not automatically terrible in Gomoku. If move ordering is weak and branching is large, transpositions may just be rare.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.