1 // search.c
2 
3 // includes
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "attack.h"
10 #include "board.h"
11 #include "colour.h"
12 #include "engine.h"
13 #include "fen.h"
14 #include "line.h"
15 #include "list.h"
16 #include "move.h"
17 #include "move_do.h"
18 #include "move_gen.h"
19 #include "move_legal.h"
20 #include "option.h"
21 #include "parse.h"
22 #include "san.h"
23 #include "search.h"
24 #include "uci.h"
25 #include "util.h"
26 
27 // variables
28 
29 static int Depth;
30 
31 static int BestMove;
32 static int BestValue;
33 static move_t BestPV[LineSize];
34 
35 static sint64 NodeNb;
36 static sint64 LeafNb;
37 static double Time;
38 
39 static int Move;
40 static int MovePos;
41 static int MoveNb;
42 
43 // prototypes
44 
45 static bool depth_is_ok (int depth);
46 static void perft       (const board_t * board, int depth);
47 
48 // functions
49 
50 // depth_is_ok()
51 
depth_is_ok(int depth)52 static bool depth_is_ok(int depth) {
53 
54    return depth >= 0 && depth < DepthMax;
55 }
56 
57 // search()
58 
search(const board_t * board,int depth_max,double time_max)59 void search(const board_t * board, int depth_max, double time_max) {
60 
61    char string[256];
62 
63    ASSERT(board_is_ok(board));
64    ASSERT(depth_max>=1&&depth_max<DepthMax);
65    ASSERT(time_max>=0.0);
66 
67    // engine
68 
69    Depth = 0;
70 
71    BestMove = MoveNone;
72    BestValue = 0;
73    line_clear(BestPV);
74 
75    NodeNb = 0;
76    LeafNb = 0;
77    Time = 0.0;
78 
79    Move = MoveNone;
80    MovePos = 0;
81    MoveNb = 0;
82 
83    // init
84 
85    uci_send_ucinewgame(Uci);
86    uci_send_isready_sync(Uci);
87 
88    // position
89 
90    if (!board_to_fen(board,string,256)) ASSERT(FALSE);
91    engine_send(Engine,"position fen %s",string);
92 
93    // search
94 
95    engine_send_queue(Engine,"go");
96 
97    engine_send_queue(Engine," movetime %.0f",time_max*1000.0);
98    engine_send_queue(Engine," depth %d",depth_max);
99 
100    engine_send(Engine,""); // newline
101 
102    // wait for feed-back
103 
104    while (!engine_eof(Engine)) {
105 
106       engine_get(Engine,string);
107 
108       if (FALSE) {
109 
110       } else if (match(string,"bestmove * ponder *")) {
111 
112          BestMove = move_from_can(Star[0],board);
113          ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board));
114 
115          break;
116 
117       } else if (match(string,"bestmove *")) {
118 
119          BestMove = move_from_can(Star[0],board);
120          ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board));
121 
122          break;
123       }
124    }
125 
126    printf("\n");
127 }
128 
129 // do_perft()
130 
do_perft(int argc,char * argv[])131 void do_perft(int argc,char * argv[]){
132     const char * fen=NULL;
133     int depth=1;
134     board_t board[1];
135     int i;
136     for (i = 1; i < argc; i++) {
137         if (FALSE) {
138         } else if (my_string_equal(argv[i],"perft")) {
139                 // skip
140         } else if (my_string_equal(argv[i],"-fen")) {
141             i++;
142             if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n");
143             my_string_set(&fen,argv[i]);
144         } else if (my_string_equal(argv[i],"-max-depth")){
145             i++;
146             if (argv[i] == NULL) my_fatal("do_perft(): missing argument\n");
147             depth=atoi(argv[i]);
148             if(depth<1) my_fatal("do_perft(): illegal depth %d\n",depth);
149         } else {
150             my_fatal("do_perft(): unknown option \"%s\"\n",argv[i]);
151         }
152     }
153     if(fen==NULL){
154         my_string_set(&fen,StartFen);
155     }
156     board_from_fen(board,fen);
157     search_perft(board,depth);
158 }
159 
160 // search_perft()
161 
search_perft(const board_t * board,int depth_max)162 void search_perft(const board_t * board, int depth_max) {
163 
164    int depth;
165    my_timer_t timer[1];
166    double time, speed;
167    char node_string[StringSize];
168    char leafnode_string[StringSize];
169 
170    ASSERT(board_is_ok(board));
171    ASSERT(depth_max>=1&&depth_max<DepthMax);
172 
173    // init
174 
175    board_disp(board);
176 
177    // iterative deepening
178 
179    for (depth = 1; depth <= depth_max; depth++) {
180 
181       // init
182 
183       NodeNb = 0;
184       LeafNb = 0;
185 
186       my_timer_reset(timer);
187 
188       my_timer_start(timer);
189       perft(board,depth);
190       my_timer_stop(timer);
191 
192       time = my_timer_elapsed_real(timer);//my_timer_elapsed_cpu(timer);
193       speed = (time < 0.01) ? 0.0 : ((double)NodeNb) / time;
194 
195       snprintf(node_string,StringSize,S64_FORMAT,NodeNb);
196       snprintf(leafnode_string,StringSize,S64_FORMAT,LeafNb);
197 
198       printf("depth=%2d nodes=%12s leafnodes=%12s time=%7.2fs nps=%8.0f\n",depth,node_string,leafnode_string,time,speed);
199    }
200 
201 }
202 
203 // perft()
204 
perft(const board_t * board,int depth)205 static void perft(const board_t * board, int depth) {
206 
207    int me;
208    list_t list[1];
209    int i, move;
210    board_t new_board[1];
211 
212    ASSERT(board_is_ok(board));
213    ASSERT(depth_is_ok(depth));
214 
215    ASSERT(!is_in_check(board,colour_opp(board->turn)));
216 
217    // init
218 
219    NodeNb++;
220 
221    // leaf
222 
223    if (depth == 0) {
224       LeafNb++;
225       return;
226    }
227 
228    // more init
229 
230    me = board->turn;
231 
232    // move loop
233 
234    gen_moves(list,board);
235 
236    for (i = 0; i < list_size(list); i++) {
237 
238       move = list_move(list,i);
239 
240       board_copy(new_board,board);
241       move_do(new_board,move);
242 
243       if (!is_in_check(new_board,me)) perft(new_board,depth-1);
244    }
245 }
246 
247 // end of search.cpp
248 
249