How can I optimize this transposition table for connect 4 AI?

71 Views Asked by At

The transposition table uses keys from the position of player 0 and player 1 from bitboards and includes the player turn at the end, I did that to guarantee unique keys for all states. But this seems to be slow because of fmt.Sprintf.

I have two functions where I store and retrieve, and in each of them I build the key and do a check or store.

type TTFlag int64

const (
    Exact      TTFlag = 0
    UpperBound TTFlag = 1
    LowerBound TTFlag = 2
)

type TTEntry struct {
    BestScore float64
    BestMove  int
    Flag      TTFlag
    Depth     int
    IsValid   bool
}

type Solver struct {
    NodeVisitCounter int
    TTMapHitCounter  int
    TTMap            map[string]TTEntry
}

func NewSolver() *Solver {
    return &Solver{
        NodeVisitCounter: 0,
        TTMapHitCounter:  0,
        TTMap:            make(map[string]TTEntry),
    }
}

func (s *Solver) StoreEntry(p *Position, entry TTEntry) {
    key := fmt.Sprintf("%d:%d:%d", p.Bitboard[0], p.Bitboard[1], p.PlayerTurn)
    s.TTMap[key] = entry
}

func (s *Solver) RetrieveEntry(p *Position) TTEntry {
    key := fmt.Sprintf("%d:%d:%d", p.Bitboard[0], p.Bitboard[1], p.PlayerTurn)
    if entry, exists := s.TTMap[key]; exists {
        s.TTMapHitCounter++
        return entry
    }
    return TTEntry{}
}

What can I do to optimize this further? How can I make better keys without the use of fmt.Sprintf and string concatenation?

Edit:

The Position struct is keeps track of game state:

type Position struct {
    Bitboard      [2]uint64
    PlayerTurn    int
    HeightBB      [7]int
    NumberOfMoves int
}

HeightBB is an array that keeps track of the height of the columns, so we know where to put the piece in the bitmap.

1

There are 1 best solutions below

1
rocka2q On BEST ANSWER

If you pay attention to the design of your data structures then I don't see any need for fmt.Sprintf.

For example,

type TTKey struct {
    Bitboard   [2]uint64
    PlayerTurn int
}

type TTFlag int64

type TTEntry struct {
    BestScore float64
    BestMove  int
    Flag      TTFlag
    Depth     int
    IsValid   bool
}

type Solver struct {
    NodeVisitCounter int
    TTMapHitCounter  int
    TTMap            map[TTKey]TTEntry
}

type Position struct {
    Key           TTKey
    HeightBB      [7]int
    NumberOfMoves int
}

func (s *Solver) StoreEntry(p *Position, entry TTEntry) {
    s.TTMap[p.Key] = entry
}

func (s *Solver) RetrieveEntry(p *Position) TTEntry {
    if entry, exists := s.TTMap[p.Key]; exists {
        s.TTMapHitCounter++
        return entry
    }
    return TTEntry{}
}