Skip to content

Commit e5ee2f4

Browse files
committed
24 Transposition table used
1 parent 9f114a4 commit e5ee2f4

File tree

4 files changed

+155
-32
lines changed

4 files changed

+155
-32
lines changed

engine.go

Lines changed: 140 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,34 @@ func (pv *pvList) String() string {
8686
return s
8787
}
8888

89+
type ebfStruct []uint64
90+
91+
func (e *ebfStruct) new() {
92+
*e = make(ebfStruct, 0, maxDepth)
93+
}
94+
func (e *ebfStruct) add(nodes uint64) {
95+
*e = append(*e, nodes)
96+
}
97+
func (e *ebfStruct) clear() {
98+
*e = (*e)[:0]
99+
}
100+
func (e *ebfStruct) ebf() float64 {
101+
if len(*e) < 4 {
102+
return 0
103+
}
104+
ebf := 0.0
105+
prevNodes1 := float64((*e)[len(*e)-2])
106+
prevNodes2 := float64((*e)[len(*e)-3])
107+
prevNodes3 := float64((*e)[len(*e)-4])
108+
109+
if prevNodes2 > 0.0 && prevNodes3 > 0.0 {
110+
ebf = (prevNodes2/prevNodes3 + prevNodes1/prevNodes2) / 2
111+
}
112+
fmt.Printf("ebf: %0.2f Stored: %v Tried: %v Found: %v Prunes: %v Best: %v\n", ebf, trans.cStores, trans.cTried, trans.cFound, trans.cPrune, trans.cBest)
113+
114+
return ebf
115+
}
116+
89117
func engine() (toEngine chan bool, frEngine chan string) {
90118
frEngine = make(chan string)
91119
toEngine = make(chan bool)
@@ -97,25 +125,31 @@ func engine() (toEngine chan bool, frEngine chan string) {
97125
//TODO root: Aspiration search
98126
func root(toEngine chan bool, frEngine chan string) {
99127
var depth, alpha, beta int
128+
var ebfTab ebfStruct
100129
var pv pvList
101130
var childPV pvList
102131
var ml moveList
103132
childPV.new()
104133
pv.new()
134+
childPV.new()
135+
// ml = make(moveList, 0, 60)
105136
ml.new(60)
137+
ebfTab.new()
106138
b := &board
107139
for _ = range toEngine {
108140
limits.startTime, limits.lastTime = time.Now(), time.Now()
109141
cntNodes = 0
110-
142+
ebfTab.clear()
111143
killers.clear()
112144
ml.clear()
113145
pv.clear()
114-
146+
trans.initSearch() // incr age coounters=0
147+
//trans.clear()
115148
genAndSort(0, b, &ml)
116149
bm := ml[0]
117150
bs := noScore
118-
depth = limits.depth
151+
depth = 0
152+
transDepth:=0
119153
for depth = 1; depth <= limits.depth && !limits.stop; depth++ {
120154
ml.sort()
121155
bs = noScore // bm keeps the best from prev iteration in case of immediate stop before first is done in this iterastion
@@ -138,30 +172,36 @@ func root(toEngine chan bool, frEngine chan string) {
138172

139173
bm = ml[ix]
140174
alpha = score
175+
transDepth = depth
176+
if depth >= 0 {
177+
trans.store(b.fullKey(), mv, transDepth, 0, score, scoreTypeLower)
178+
}
141179

142180
t1 := time.Since(limits.startTime)
143181
tell(fmt.Sprintf("info score cp %v depth %v nodes %v time %v pv ", bm.eval(), depth, cntNodes, int(t1.Seconds()*1000)), pv.String())
144182
}
145-
146183
}
147-
ml.sort()
184+
185+
ebfTab.add(cntNodes)
148186
}
149-
//
187+
ml.sort()
188+
189+
trans.store(b.fullKey(), bm, transDepth, 0, bs, scoreType(bs, alpha, beta))
190+
150191
// time, nps, ebf
151192
t1 := time.Since(limits.startTime)
152193
nps := float64(0)
153194
if t1.Seconds() != 0 {
154195
nps = float64(cntNodes) / t1.Seconds()
155196
}
156-
197+
ebfTab.ebf()
157198
tell(fmt.Sprintf("info score cp %v depth %v nodes %v time %v nps %v pv %v", bm.eval(), depth-1, cntNodes, int(t1.Seconds()*1000), uint(nps), pv.String()))
158199
frEngine <- fmt.Sprintf("bestmove %v%v", sq2Fen[bm.fr()], sq2Fen[bm.to()])
159200
}
160201
}
161202

162-
//TODO search: qs with SEE
163-
164203
//TODO search: hash table/transposition table
204+
165205
//TODO search: history table and maybe counter move table
166206
//TODO search: move generation. More fast and accurate
167207
//TODO search: Null Move
@@ -178,15 +218,42 @@ func search(alpha, beta, depth, ply int, pv *pvList, b *boardStruct) int {
178218
}
179219
pv.clear()
180220

181-
// trans retrieve here
221+
transMove := noMove
222+
transDepth := depth
223+
pvNode := depth > 0 && beta != alpha+1
224+
225+
if depth < 0 { // inCheck?
226+
transDepth = 0
227+
}
228+
{ // keep spme variables local just to be sure
229+
var transSc, scType int
230+
ok := false
231+
232+
if transMove, transSc, scType, ok = trans.retrieve(b.fullKey(), transDepth, ply); ok && !pvNode {
233+
switch {
234+
case scType == scoreTypeLower && transSc >= beta:
235+
trans.cPrune++
236+
return transSc
237+
case scType == scoreTypeUpper && transSc <= alpha:
238+
trans.cPrune++
239+
return transSc
240+
case scType == scoreTypeBetween:
241+
trans.cPrune++
242+
return transSc
243+
}
244+
}
245+
}
182246

183247
var ml moveList
248+
//ml= make(moveList, 0, 60)
184249
ml.new(60)
185250

186251
//genAndSort(b, &ml)
187-
genInOrder(b, &ml, ply)
252+
genInOrder(b, &ml, ply, transMove)
253+
188254

189-
bs := noScore
255+
bs,score := noScore, noScore
256+
bm := noMove
190257
var childPV pvList
191258
childPV.new() // TODO? make it smaller for each depth maxDepth-ply
192259
for _, mv := range ml {
@@ -196,36 +263,63 @@ func search(alpha, beta, depth, ply int, pv *pvList, b *boardStruct) int {
196263

197264
childPV.clear()
198265

199-
score := -search(-beta, -alpha, depth-1, ply+1, &childPV, b)
200-
266+
/* if pvNode && bm != noMove {
267+
score = -search(-alpha-1, -alpha, depth-1, ply+1, &childPV, b)
268+
if score > alpha { // PVS/LMR re-search
269+
score = -search(-beta, -alpha, depth-1, ply+1, &childPV, b)
270+
}
271+
} else {
272+
*/
273+
score = -search(-beta, -alpha, depth-1, ply+1, &childPV, b)
274+
// }
275+
201276
b.unmove(mv)
202277

203278
if score > bs {
204279
bs = score
280+
bm = mv
205281
pv.catenate(mv, &childPV)
206282
if score > alpha {
207283
alpha = score
208-
// trans.store here
284+
trans.store(b.fullKey(), mv, depth, ply, score, scoreType(score, alpha, beta))
209285
}
210286

211287
if score >= beta { // beta cutoff
212288
// add killer and update history
213289
if mv.cp() == empty && mv.pr() == empty {
214290
killers.add(mv, ply)
215291
}
292+
if mv.cmp(transMove) {
293+
trans.cPrune++
294+
}
216295
return score
217296
}
218297
}
219-
if time.Since(limits.lastTime) >= time.Duration(time.Second) {
298+
299+
tStep := time.Since(limits.lastTime) - time.Duration(time.Millisecond*200)
300+
if tStep >= 0 {
301+
limits.lastTime = time.Now().Add(-time.Duration(tStep))
220302
t1 := time.Since(limits.startTime)
221-
tell(fmt.Sprintf("info time %v nodes %v nps %v", int(t1.Seconds()*1000), cntNodes, cntNodes/uint64(t1.Seconds())))
222-
limits.lastTime = time.Now()
303+
ms := uint64(t1.Nanoseconds() / 1000000)
304+
if t1.Seconds() > 1 {
305+
if ms%1000 <= 5 {
306+
tell(fmt.Sprintf("info time %v nodes %v nps %v", ms, cntNodes, cntNodes/uint64(t1.Seconds())))
307+
}
308+
}
309+
310+
if ms >= uint64(limits.moveTime)-200 {
311+
// fmt.Println("t1", uint64(t1.Nanoseconds()/1000000)-100, "limit", uint64(limits.moveTime))
312+
limits.stop = true
313+
}
223314
}
224315

225316
if limits.stop {
226317
return alpha
227318
}
228319
}
320+
if bm.cmp(transMove) {
321+
trans.cBest++
322+
}
229323
return bs
230324
}
231325

@@ -413,24 +507,45 @@ func genAndSort(ply int, b *boardStruct, ml *moveList) {
413507
}
414508

415509
// generate capture moves first, then killers, then non captures
416-
func genInOrder(b *boardStruct, ml *moveList, ply int) {
510+
func genInOrder(b *boardStruct, ml *moveList, ply int, transMove move) {
417511
ml.clear()
418512
b.genAllCaptures(ml)
419513
noCaptIx := len(*ml)
420514
b.genAllNonCaptures(ml)
515+
if transMove != noMove {
516+
for ix := 0; ix < len(*ml); ix++ {
517+
mv := (*ml)[ix]
518+
if transMove.cmp(mv) {
519+
(*ml)[ix], (*ml)[0] = (*ml)[0], (*ml)[ix]
520+
break
521+
}
522+
}
523+
}
524+
pos1, pos2 := noCaptIx, noCaptIx+1
525+
if (*ml)[pos1].cmp(transMove) {
526+
noCaptIx++
527+
pos1++
528+
pos2++
529+
}
421530

422531
if len(*ml)-noCaptIx > 2 {
423-
// place killers first among non captuers
532+
// place killers first among non captures
533+
cnt := 0
424534
for ix := noCaptIx; ix < len(*ml); ix++ {
425535
mv := (*ml)[ix]
426-
if killers[ply].k1.cmpFrTo(mv) {
427-
(*ml)[ix], (*ml)[noCaptIx] = (*ml)[noCaptIx], (*ml)[ix]
428-
} else if killers[ply].k2.cmpFrTo(mv) {
429-
(*ml)[ix], (*ml)[noCaptIx+1] = (*ml)[noCaptIx+1], (*ml)[ix]
536+
switch {
537+
case killers[ply].k1.cmp(mv) && !mv.cmp(transMove):
538+
(*ml)[ix], (*ml)[pos1] = (*ml)[pos1], (*ml)[ix]
539+
cnt++
540+
case killers[ply].k2.cmp(mv) && !mv.cmp(transMove):
541+
(*ml)[ix], (*ml)[pos2] = (*ml)[pos2], (*ml)[ix]
542+
cnt++
543+
}
544+
if cnt >= 2 {
545+
break
430546
}
431547
}
432548
}
433-
434549
}
435550

436551
func signEval(stm color, ev int) int {

main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package main
22

3+
import (
4+
"strings"
5+
)
6+
37
func main() {
48
tell("info string Starting GoBit")
59

@@ -17,4 +21,6 @@ func init() {
1721
initCastlings()
1822
pcSqInit()
1923
board.newGame()
24+
handleSetOption(strings.Split("setoption name hash value 32", " "))
25+
2026
}

trans.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func (t *transpStruct) new(mB int) error {
122122
t.cntUsed = 0
123123

124124
t.tab = make([]ttEntry, t.entries, t.entries)
125-
125+
t.clear()
126126
tell(fmt.Sprintf("info string allocated %v MB to %v entries", len(t.tab)*entrySize/(1024*1024), t.entries))
127127
return nil
128128
}
@@ -313,9 +313,9 @@ func isMateScore(sc int) bool {
313313
// in order to mix up different depths
314314
func removeMatePly(sc, ply int) int {
315315
if sc < minEval+maxPly {
316-
return sc - ply
316+
return -mateEval
317317
} else if sc > maxEval-maxPly {
318-
return sc + ply
318+
return mateEval
319319
} else {
320320
return sc
321321
}
@@ -324,9 +324,9 @@ func removeMatePly(sc, ply int) int {
324324
// addMatePly adjusts mate value with ply if mate score
325325
func addMatePly(sc, ply int) int {
326326
if sc < minEval+maxPly {
327-
return sc + ply
328-
} else if sc > maxEval+maxPly {
329-
return sc - ply
327+
return mateEval - ply
328+
} else if sc > maxEval-maxPly {
329+
return -mateEval+ply
330330
}
331331
return sc
332332
}

uci.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func uci(input chan string) {
3939
case "isready":
4040
handleIsReady()
4141
case "ucinewgame":
42+
trans.clear()
4243
handleNewgame()
4344
case "position":
4445
handlePosition(cmd)
@@ -99,7 +100,7 @@ func uci(input chan string) {
99100
func handleUci() {
100101
tell("id name GoBit")
101102
tell("id author Carokanns")
102-
103+
103104
tell("option name Hash type spin default 128 min 16 max 1024")
104105
tell("option name Threads type spin default 1 min 1 max 16")
105106
tell("uciok")
@@ -266,6 +267,7 @@ func handleMyPositions(words []string){
266267

267268
words[1] = trim(low(words[1]))
268269
handleSetOption(strings.Split("setoption name hash value 256"," "))
270+
trans.clear()
269271
switch words[1]{
270272
case "london": handlePosition("position startpos moves d2d4 d7d5 c1f4 g8f6 e2e3 c7c5 b1d2 b8c6 c2c3 e7e6 f1d3 f8d6")
271273
case "phil": handlePosition("position startpos moves e2e4 d7d6 d2d4 e7e5 d4e5 d6e5 d1d8 e8d8 g1f3 f7f6 b1c3 c7c6 f1c4")

0 commit comments

Comments
 (0)