@@ -3,19 +3,30 @@ package main
33import (
44 "fmt"
55 "math"
6+ "time"
67)
78
9+ const (
10+ maxDepth = 100
11+ maxPly = 100
12+ )
13+
14+ var cntNodes uint64
815
916//TODO search limits: start clock and testing for movetime
1017//TODO search limits: counting nodes and testing for limit.nodes
11- //TODO search limits: depth and other limits
18+ //TODO search limits: limit.depth
19+
1220//TODO search limits: time per game w/wo increments
1321//TODO search limits: time per x moves and after x moves w/wo increments
1422type searchLimits struct {
15- depth int
16- nodes uint64
17- moveTime int // in milliseconds
18- infinite bool
23+ depth int
24+ nodes uint64
25+ moveTime int // in milliseconds
26+ infinite bool
27+ startTime time.Time
28+ nextTime time.Time
29+
1930 //////////////// current //////////
2031 stop bool
2132}
@@ -27,6 +38,7 @@ func (s *searchLimits) init() {
2738 s .nodes = math .MaxUint64
2839 s .moveTime = 99999999999
2940 s .infinite = false
41+ s .stop = false
3042}
3143
3244func (s * searchLimits ) setStop (st bool ) {
@@ -42,6 +54,38 @@ func (s *searchLimits) setInfinite(b bool) {
4254 s .infinite = b
4355}
4456
57+ type pvList []move
58+
59+ func (pv * pvList ) new () {
60+ * pv = make (pvList , 0 , maxPly )
61+ }
62+
63+ func (pv * pvList ) add (mv move ) {
64+ * pv = append (* pv , mv )
65+ }
66+
67+ func (pv * pvList ) clear () {
68+ * pv = (* pv )[:0 ]
69+ }
70+
71+ func (pv * pvList ) addPV (pv2 * pvList ) {
72+ * pv = append (* pv , * pv2 ... )
73+ }
74+
75+ func (pv * pvList ) catenate (mv move , pv2 * pvList ) {
76+ pv .clear ()
77+ pv .add (mv )
78+ pv .addPV (pv2 )
79+ }
80+
81+ func (pv * pvList ) String () string {
82+ s := ""
83+ for _ , mv := range * pv {
84+ s += mv .String () + " "
85+ }
86+ return s
87+ }
88+
4589func engine () (toEngine chan bool , frEngine chan string ) {
4690 fmt .Println ("info string Hello from engine" )
4791 frEngine = make (chan string )
@@ -52,32 +96,53 @@ func engine() (toEngine chan bool, frEngine chan string) {
5296}
5397
5498//TODO root: Iterative Depening
99+
55100//TODO root: Aspiration search
56101func root (toEngine chan bool , frEngine chan string ) {
102+ var pv pvList
103+ var childPV pvList
104+ childPV .new ()
57105 b := & board
58- ml := moveList {}
106+ ml := make ( moveList , 0 , 60 )
59107 for _ = range toEngine {
60- tell ("info string engine got go! X" )
61- ml = moveList {}
108+ limits .startTime , limits .nextTime = time .Now (), time .Now ()
109+ alpha , beta := - minEval , maxEval
110+ bm , bs := noMove , noScore
111+ depth := limits .depth
112+ cntNodes = 0
113+ ml .clear ()
62114 genAndSort (b , & ml )
63115
64- for _ , mv := range ml {
65- b .move (mv )
66- score := - search (b )
67- b .unmove (mv )
68-
69- mv .packEval (adjEval (b , score ))
116+ for ix := range ml {
117+ mv := & ml [ix ]
118+ childPV .clear ()
119+
120+ b .move (* mv )
121+ tell ("info currmove " , mv .String ())
122+ score := - search (- beta , - alpha , depth - 1 , 1 , & childPV , b )
123+ b .unmove (* mv )
124+ mv .packEval (signEval (b .stm , score ))
125+ if score > bs {
126+ bs = score
127+ pv .clear ()
128+ pv .catenate (* mv , & childPV )
129+
130+ bm = * mv
131+ alpha = score
132+ tell (fmt .Sprintf ("info score cp %v depth %v nodes %v pv " , bs , depth , cntNodes ), pv .String ())
133+ }
70134 }
71135 ml .sort ()
72- tell ("info score cp " , fmt . Sprintf ( "%v " , ml [ 0 ] .eval ()), " depth 1 pv " , ml [ 0 ] .String ())
136+ tell (fmt . Sprintf ( "info score cp %v depth %v nodes %v pv " , bm .eval (), depth , cntNodes ), pv .String ())
73137 frEngine <- fmt .Sprintf ("bestmove %v%v" , sq2Fen [ml [0 ].fr ()], sq2Fen [ml [0 ].to ()])
74138 }
75139}
76140
77141//TODO search: the 'stop' command
78142//TODO search: time handling basic movetime
79- //TODO search: generate all moves and put captures first (temporary)
80143//TODO search: alpha Beta
144+
145+ //TODO search: generate all moves and put captures first (temporary)
81146//TODO search: qs
82147//TODO search: killer moves
83148//TODO search: hash table
@@ -90,27 +155,65 @@ func root(toEngine chan bool, frEngine chan string) {
90155//TODO search: more complicated time handling schemes
91156//TODO search: other reductions and extensions
92157
93- func search (b * boardStruct ) int {
158+ func search (alpha , beta , depth , ply int , pv * pvList , b * boardStruct ) int {
159+ cntNodes ++
160+ if depth <= 0 {
161+ return signEval (b .stm ,evaluate (b ))
162+ }
163+ pv .clear ()
164+ ml := make (moveList , 0 , 60 )
165+ genAndSort (b , & ml )
166+
167+ bm , bs := noMove , noScore
168+ var childPV pvList
169+ for _ , mv := range ml {
170+ childPV .clear ()
171+ b .move (mv )
172+ score := - search (- beta , - alpha , depth - 1 , ply + 1 , & childPV , b )
173+ b .unmove (mv )
174+ if score > bs {
175+ bs = score
176+ pv .catenate (mv , & childPV )
177+
178+ if score >= beta { // beta cutoff
179+ return score
180+ }
181+ if score > alpha {
182+ bm = mv
183+ _ = bm
184+ alpha = score
185+ }
186+ }
187+ if time .Since (limits .nextTime ) >= time .Duration (time .Second ) {
188+ t1 := time .Since (limits .startTime )
189+ tell (fmt .Sprintf ("info time %v nodes %v nps %v" , int (t1 .Seconds ()* 1000 ), cntNodes , cntNodes / uint64 (t1 .Seconds ())))
190+ limits .nextTime = time .Now ()
191+ }
94192
95- return evaluate (b )
193+ if limits .stop {
194+ return alpha
195+ }
196+ }
197+ return bs
96198}
97199
98200func genAndSort (b * boardStruct , ml * moveList ) {
201+
99202 b .genAllMoves (ml )
100203
101204 for ix , mv := range * ml {
102205 b .move (mv )
103206 v := evaluate (b )
104207 b .unmove (mv )
105- v = adjEval ( b , v )
208+ v = signEval ( b . stm , v )
106209 (* ml )[ix ].packEval (v )
107210 }
108211
109212 ml .sort ()
110213}
111214
112- func adjEval ( b * boardStruct , ev int ) int {
113- if b . stm == BLACK {
215+ func signEval ( stm color , ev int ) int {
216+ if stm == BLACK {
114217 return - ev
115218 }
116219 return ev
0 commit comments