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
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