...

Source file src/code.rocket9labs.com/tslocum/tabula/analysis.go

Documentation: code.rocket9labs.com/tslocum/tabula

     1  package tabula
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"sync"
     7  )
     8  
     9  var Verbose bool
    10  
    11  var QueueBufferSize = 4096000
    12  
    13  var (
    14  	WeightBlot     = 0.9
    15  	WeightHit      = -1.0
    16  	WeightOppScore = -0.9
    17  )
    18  
    19  // rollProbabilities is a table of the probability of each roll combination.
    20  var rollProbabilities = [21][3]int{
    21  	{1, 1, 1},
    22  	{1, 2, 2},
    23  	{1, 3, 2},
    24  	{1, 4, 2},
    25  	{1, 5, 2},
    26  	{1, 6, 2},
    27  	{2, 2, 1},
    28  	{2, 3, 2},
    29  	{2, 4, 2},
    30  	{2, 5, 2},
    31  	{2, 6, 2},
    32  	{3, 3, 1},
    33  	{3, 4, 2},
    34  	{3, 5, 2},
    35  	{3, 6, 2},
    36  	{4, 4, 1},
    37  	{4, 5, 2},
    38  	{4, 6, 2},
    39  	{5, 5, 1},
    40  	{5, 6, 2},
    41  	{6, 6, 1},
    42  }
    43  
    44  var analysisQueue = make(chan *Analysis, QueueBufferSize)
    45  
    46  func init() {
    47  	cpus := runtime.NumCPU()
    48  	if cpus < 1 {
    49  		cpus = 1
    50  	}
    51  	for i := 0; i < cpus; i++ {
    52  		go analyzer()
    53  	}
    54  }
    55  
    56  type Analysis struct {
    57  	Board Board
    58  	Moves [4][2]int8
    59  	Past  bool
    60  	Score float64
    61  
    62  	Pips        int
    63  	Blots       int
    64  	Hits        int
    65  	PlayerScore float64
    66  
    67  	result      *[]*Analysis
    68  	resultMutex *sync.Mutex
    69  
    70  	OppPips  float64
    71  	OppBlots float64
    72  	OppHits  float64
    73  	OppScore float64
    74  
    75  	player   int8
    76  	hitScore int
    77  	chance   int
    78  	wg       *sync.WaitGroup
    79  }
    80  
    81  func (a *Analysis) _analyze() {
    82  	var hs int
    83  	o := opponent(a.player)
    84  	for i := 0; i < 4; i++ {
    85  		move := a.Moves[i]
    86  		if move[0] == 0 && move[1] == 0 {
    87  			break
    88  		}
    89  		checkers := checkers(o, a.Board[move[1]])
    90  		if checkers == 1 {
    91  			hs += PseudoPips(a.player, move[1], a.Board[SpaceVariant])
    92  		}
    93  		a.Board = a.Board.UseRoll(move[0], move[1], a.player).Move(move[0], move[1], a.player)
    94  	}
    95  	if !a.Past {
    96  		a.Past = a.Board.Past()
    97  	}
    98  	a.Board.evaluate(a.player, hs, a)
    99  
   100  	if a.player == 1 && !a.Past {
   101  		a.wg.Add(21)
   102  		for j := 0; j < 21; j++ {
   103  			j := j
   104  			go func() {
   105  				check := rollProbabilities[j]
   106  				bc := a.Board
   107  				bc[SpaceRoll1], bc[SpaceRoll2] = int8(check[0]), int8(check[1])
   108  				if check[0] == check[1] {
   109  					bc[SpaceRoll3], bc[SpaceRoll4] = int8(check[0]), int8(check[1])
   110  				} else {
   111  					bc[SpaceRoll3], bc[SpaceRoll4] = 0, 0
   112  				}
   113  				available, _ := bc.Available(2)
   114  				if len(available) == 0 {
   115  					{
   116  						a := &Analysis{
   117  							Board:       bc,
   118  							Past:        a.Past,
   119  							player:      2,
   120  							chance:      check[2],
   121  							result:      a.result,
   122  							resultMutex: a.resultMutex,
   123  						}
   124  						bc.evaluate(a.player, 0, a)
   125  						a.resultMutex.Lock()
   126  						for i := 0; i < a.chance; i++ {
   127  							*a.result = append(*a.result, a)
   128  						}
   129  						a.resultMutex.Unlock()
   130  					}
   131  					a.wg.Done()
   132  					return
   133  				}
   134  				a.wg.Add(len(available))
   135  				for _, moves := range available {
   136  					a := &Analysis{
   137  						Board:       bc,
   138  						Moves:       moves,
   139  						Past:        a.Past,
   140  						player:      2,
   141  						chance:      check[2],
   142  						result:      a.result,
   143  						resultMutex: a.resultMutex,
   144  						wg:          a.wg,
   145  					}
   146  					analysisQueue <- a
   147  				}
   148  				a.wg.Done()
   149  			}()
   150  		}
   151  	} else if a.player == 2 {
   152  		a.resultMutex.Lock()
   153  		for i := 0; i < a.chance; i++ {
   154  			*a.result = append(*a.result, a)
   155  		}
   156  		a.resultMutex.Unlock()
   157  	}
   158  	a.wg.Done()
   159  }
   160  
   161  func (a *Analysis) String() string {
   162  	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)
   163  }
   164  
   165  func analyzer() {
   166  	var a *Analysis
   167  	for {
   168  		a = <-analysisQueue
   169  		a._analyze()
   170  	}
   171  }
   172  

View as plain text