@@ -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+
89117func 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
98126func 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
436551func signEval (stm color , ev int ) int {
0 commit comments