tabula/analysis.go

172 lines
3.3 KiB
Go
Raw Normal View History

package tabula
import (
"fmt"
2023-12-06 23:58:31 +00:00
"runtime"
2023-12-06 22:02:04 +00:00
"sync"
)
2023-12-23 08:49:35 +00:00
var Verbose bool
2023-12-11 20:15:26 +00:00
var QueueBufferSize = 4096000
2023-12-06 23:58:31 +00:00
2023-12-06 22:02:04 +00:00
var (
2024-01-18 04:46:01 +00:00
WeightBlot = 0.9
2023-12-09 09:44:35 +00:00
WeightHit = -1.0
2024-01-18 04:46:01 +00:00
WeightOppScore = -0.9
2023-12-06 22:02:04 +00:00
)
// rollProbabilities is a table of the probability of each roll combination.
var rollProbabilities = [21][3]int{
{1, 1, 1},
{1, 2, 2},
{1, 3, 2},
{1, 4, 2},
{1, 5, 2},
{1, 6, 2},
{2, 2, 1},
{2, 3, 2},
{2, 4, 2},
{2, 5, 2},
{2, 6, 2},
{3, 3, 1},
{3, 4, 2},
{3, 5, 2},
{3, 6, 2},
{4, 4, 1},
{4, 5, 2},
{4, 6, 2},
{5, 5, 1},
{5, 6, 2},
{6, 6, 1},
}
2023-12-11 20:15:26 +00:00
var analysisQueue = make(chan *Analysis, QueueBufferSize)
2023-12-06 23:58:31 +00:00
func init() {
cpus := runtime.NumCPU()
if cpus < 1 {
cpus = 1
}
for i := 0; i < cpus; i++ {
go analyzer()
}
}
type Analysis struct {
Board Board
Moves [4][2]int8
2023-12-02 19:25:07 +00:00
Past bool
Score float64
Pips int
Blots int
Hits int
PlayerScore float64
2023-12-06 23:58:31 +00:00
result *[]*Analysis
resultMutex *sync.Mutex
OppPips float64
OppBlots float64
OppHits float64
OppScore float64
2024-01-08 05:28:21 +00:00
player int8
hitScore int
2023-12-06 22:02:04 +00:00
chance int
2023-12-06 23:58:31 +00:00
wg *sync.WaitGroup
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
func (a *Analysis) _analyze() {
2023-12-06 22:02:04 +00:00
var hs int
o := opponent(a.player)
for i := 0; i < 4; i++ {
2023-12-06 22:02:04 +00:00
move := a.Moves[i]
if move[0] == 0 && move[1] == 0 {
break
}
checkers := checkers(o, a.Board[move[1]])
2023-12-06 22:02:04 +00:00
if checkers == 1 {
hs += PseudoPips(a.player, move[1], a.Board[SpaceVariant])
2023-12-06 22:02:04 +00:00
}
2024-01-08 05:28:21 +00:00
a.Board = a.Board.UseRoll(move[0], move[1], a.player).Move(move[0], move[1], a.player)
2023-12-06 22:02:04 +00:00
}
2023-12-09 09:44:35 +00:00
if !a.Past {
a.Past = a.Board.Past()
}
2023-12-06 22:02:04 +00:00
a.Board.evaluate(a.player, hs, a)
if a.player == 1 && !a.Past {
2023-12-06 23:58:31 +00:00
a.wg.Add(21)
2023-12-06 22:02:04 +00:00
for j := 0; j < 21; j++ {
j := j
go func() {
check := rollProbabilities[j]
bc := a.Board
bc[SpaceRoll1], bc[SpaceRoll2] = int8(check[0]), int8(check[1])
if check[0] == check[1] {
bc[SpaceRoll3], bc[SpaceRoll4] = int8(check[0]), int8(check[1])
} else {
bc[SpaceRoll3], bc[SpaceRoll4] = 0, 0
}
available, _ := bc.Available(2)
if len(available) == 0 {
2023-12-06 23:58:31 +00:00
{
a := &Analysis{
Board: bc,
Past: a.Past,
player: 2,
chance: check[2],
result: a.result,
resultMutex: a.resultMutex,
}
bc.evaluate(a.player, 0, a)
a.resultMutex.Lock()
for i := 0; i < a.chance; i++ {
*a.result = append(*a.result, a)
}
a.resultMutex.Unlock()
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
a.wg.Done()
2023-12-06 22:02:04 +00:00
return
}
2023-12-06 23:58:31 +00:00
a.wg.Add(len(available))
2023-12-06 22:02:04 +00:00
for _, moves := range available {
a := &Analysis{
2023-12-06 23:58:31 +00:00
Board: bc,
Moves: moves,
Past: a.Past,
player: 2,
chance: check[2],
result: a.result,
resultMutex: a.resultMutex,
wg: a.wg,
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
analysisQueue <- a
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
a.wg.Done()
2023-12-06 22:02:04 +00:00
}()
}
2023-12-06 23:58:31 +00:00
} else if a.player == 2 {
a.resultMutex.Lock()
for i := 0; i < a.chance; i++ {
*a.result = append(*a.result, a)
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
a.resultMutex.Unlock()
2023-12-06 22:02:04 +00:00
}
2023-12-06 23:58:31 +00:00
a.wg.Done()
}
func (a *Analysis) String() string {
2023-12-02 19:25:07 +00:00
return fmt.Sprintf("Moves: %s Score: %.2f - Score: %.2f Pips: %d Blots: %d Hits: %d / Score: %.2f Pips: %.2f Blots: %.2f Hits: %.2f Past: %v", fmt.Sprint(a.Moves), a.Score, a.PlayerScore, a.Pips, a.Blots, a.Hits, a.OppScore, a.OppPips, a.OppBlots, a.OppHits, a.Past)
}
2023-12-06 23:58:31 +00:00
func analyzer() {
var a *Analysis
for {
a = <-analysisQueue
a._analyze()
}
}