-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementing Parallel search algorithm ABDADA #95
New TranspositionTableEntry type, concurrent read for ABDADA
- Loading branch information
Showing
6 changed files
with
246 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package ai | ||
|
||
import ( | ||
"fmt" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/board" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/color" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/location" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/transposition_table" | ||
"time" | ||
) | ||
|
||
func (ab *ABDADA) ABDADA(root *board.Board, depth, alpha, beta int, exclusiveProbe bool, currentPlayer color.Color, previousMove *board.LastMove) *ScoredMove { | ||
if depth == 0 { | ||
return &ScoredMove{ | ||
Score: ab.player.EvaluateBoard(root, ab.player.PlayerColor).TotalScore, | ||
} | ||
} else { | ||
var best ScoredMove | ||
|
||
answerChan := ab.asyncTTRead(root, uint16(depth), alpha, beta, currentPlayer, exclusiveProbe) | ||
// generate moves while waiting for the answer ... | ||
moves := root.GetAllMoves(currentPlayer, previousMove) | ||
|
||
// block and grab the answer | ||
ttAnswer := <-answerChan | ||
|
||
} | ||
} | ||
|
||
type ABDADA struct { | ||
player *AIPlayer | ||
currentSearchDepth int | ||
lastSearchDepth int | ||
lastSearchTime time.Duration | ||
} | ||
|
||
func (ab *ABDADA) GetName() string { | ||
return fmt.Sprintf("%s,[D:%d;T:%s]", AlgorithmABDADA, ab.lastSearchDepth, ab.lastSearchTime) | ||
} | ||
|
||
func (ab *ABDADA) GetBestMove(p *AIPlayer, b *board.Board, previousMove *board.LastMove) *ScoredMove { | ||
ab.player = p | ||
} | ||
|
||
type TTAnswer struct { | ||
alpha, beta, score int | ||
bestMove location.Move | ||
onEvaluation bool | ||
} | ||
|
||
func (ab *ABDADA) asyncTTRead(root *board.Board, depth uint16, alpha, beta int, currentPlayer color.Color, exclusiveProbe bool) chan TTAnswer { | ||
answerChan := make(chan TTAnswer) | ||
go func(answerChan chan TTAnswer) { | ||
answer := TTAnswer{ | ||
alpha: alpha, | ||
beta: beta, | ||
score: NegInf, | ||
} | ||
if ab.player.TranspositionTableEnabled { | ||
// transposition table lookup | ||
h := root.Hash() | ||
if e, ok := ab.player.alphaBetaTable.Read(&h, currentPlayer); ok { | ||
entry := e.(*transposition_table.TranspositionTableEntryABDADA) | ||
entry.Lock.Lock() | ||
|
||
if entry.Depth == depth && exclusiveProbe && entry.NumProcessors > 0 { | ||
answer.onEvaluation = true | ||
} else if entry.Depth >= depth { | ||
if entry.EntryType == transposition_table.TrueScore { | ||
answer.score = entry.Score | ||
answer.alpha = entry.Score | ||
answer.beta = entry.Score | ||
} else if entry.EntryType == transposition_table.UpperBound && entry.Score < beta { | ||
answer.score = entry.Score | ||
answer.beta = entry.Score | ||
} else if entry.EntryType == transposition_table.LowerBound && entry.Score > alpha { | ||
answer.score = entry.Score | ||
answer.alpha = entry.Score | ||
} | ||
|
||
if entry.Depth == depth && answer.alpha < answer.beta { | ||
// Increment the number of processors evaluating this node | ||
entry.NumProcessors++ | ||
} | ||
} else { | ||
// This is the first processor to evaluate this node | ||
entry.Depth = depth | ||
entry.EntryType = transposition_table.Unset | ||
entry.NumProcessors = 1 | ||
} | ||
|
||
entry.Lock.Unlock() | ||
} | ||
} | ||
answerChan <- answer | ||
}(answerChan) | ||
return answerChan | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package transposition_table | ||
|
||
import ( | ||
"fmt" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/location" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/util" | ||
"sync" | ||
) | ||
|
||
type TranspositionTableEntryABMemory struct { | ||
Lower, Upper int | ||
BestMove location.Move | ||
} | ||
|
||
const ( | ||
Unset = byte(iota) | ||
UpperBound = byte(iota) | ||
LowerBound = byte(iota) | ||
TrueScore = byte(iota) | ||
) | ||
|
||
type TranspositionTableEntryABDADA struct { | ||
Score int | ||
BestMove location.Move | ||
|
||
// Flag that identifies the entry | ||
EntryType byte | ||
|
||
// Length of subtree upon which score is based. | ||
Depth uint16 | ||
|
||
// The number of processors currently evaluating the node related to the transposition table entry | ||
NumProcessors uint16 | ||
|
||
Lock sync.Mutex | ||
} | ||
|
||
type TranspositionTable struct { | ||
entryMap map[util.BoardHash]map[byte]interface{} | ||
numStored int | ||
numReads, numHits int | ||
} | ||
|
||
func NewTranspositionTable() *TranspositionTable { | ||
var m TranspositionTable | ||
if m.entryMap == nil { | ||
m.entryMap = make(map[util.BoardHash]map[byte]interface{}) | ||
} | ||
return &m | ||
} | ||
|
||
/* | ||
Note: Transposition table does not support concurrent read/write at the moment | ||
*/ | ||
func (m *TranspositionTable) Store(hash *util.BoardHash, currentTurn byte, entry interface{}) { | ||
_, ok := m.entryMap[*hash] | ||
if !ok { | ||
m.entryMap[*hash] = make(map[byte]interface{}) | ||
} | ||
m.entryMap[*hash][currentTurn] = entry | ||
m.numStored++ | ||
} | ||
|
||
func (m *TranspositionTable) Read(hash *util.BoardHash, currentTurn byte) (interface{}, bool) { | ||
m.numReads++ | ||
|
||
m1, ok := m.entryMap[*hash] | ||
if ok { | ||
v, ok := m1[currentTurn] | ||
if ok { | ||
m.numHits++ | ||
return v, true | ||
} | ||
} | ||
return nil, false | ||
} | ||
|
||
func (m *TranspositionTable) PrintMetrics() (result string) { | ||
result += fmt.Sprintf("\tTotal entries in transposition table %d\n", m.numStored) | ||
result += fmt.Sprintf("\tHit ratio %f%% (%d/%d)\n", 100.0*float64(m.numHits)/float64(m.numReads), | ||
m.numHits, m.numReads) | ||
return | ||
} |
43 changes: 43 additions & 0 deletions
43
pkg/chessai/transposition_table/transposition_table_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package transposition_table | ||
|
||
import ( | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/board" | ||
"github.com/Vadman97/ChessAI3/pkg/chessai/color" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestTranspositionTable_StoreUpdateReadABDADA(t *testing.T) { | ||
tt := NewTranspositionTable() | ||
|
||
b := board.Board{} | ||
b.ResetDefault() | ||
b.RandomizeIllegal() | ||
h := b.Hash() | ||
|
||
ttEntry := TranspositionTableEntryABDADA{} | ||
tt.Store(&h, color.Black, &ttEntry) | ||
ttEntry.NumProcessors++ | ||
|
||
assert.Equal(t, uint16(1), ttEntry.NumProcessors) | ||
|
||
e, _ := tt.Read(&h, color.Black) | ||
readEntry := e.(*TranspositionTableEntryABDADA) | ||
|
||
assert.Equal(t, uint16(1), readEntry.NumProcessors) | ||
readEntry.NumProcessors++ | ||
|
||
assert.Equal(t, uint16(2), readEntry.NumProcessors) | ||
assert.Equal(t, uint16(2), ttEntry.NumProcessors) | ||
|
||
newEntry := TranspositionTableEntryABDADA{} | ||
tt.Store(&h, color.Black, &newEntry) | ||
|
||
assert.Equal(t, uint16(2), readEntry.NumProcessors) | ||
assert.Equal(t, uint16(2), ttEntry.NumProcessors) | ||
|
||
e, _ = tt.Read(&h, color.Black) | ||
readEntry = e.(*TranspositionTableEntryABDADA) | ||
|
||
assert.Equal(t, uint16(0), readEntry.NumProcessors) | ||
} |
Oops, something went wrong.