search: fixed a bug in NULL move pruning
[owl.git] / cmd.c
blob172ca9f3c8d8ffb2f6f032208f5206d188ad06dd
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 #include "common.h"
17 #include "board.h"
18 #include "engine.h"
19 #include "evaluate.h"
20 #include "move.h"
21 #include "search.h"
23 /* forward declarations of functions */
24 static void init_protover_2(void);
25 static int parse_cmd(char *cmd);
27 /* wait for a command */
28 void
29 loopcmd(void)
31 int i;
32 int res;
33 int move;
34 int engine_xboard;
35 char cmd[MAX_STRING];
36 char move_buf[MAX_STRING];
37 pthread_t tid;
39 while (TRUE) {
40 if (get_engine_value(&e.side) == brd.wtm &&
41 !get_engine_value(&e.force_mode)) {
42 /* start thinking in separate thread */
43 res = pthread_create(&tid, 0, process_turn, 0);
45 /* error occured */
46 if (res) {
47 fprintf(stderr, "pthread error: %s\n", strerror(res));
48 perform_cleanup();
49 exit(res);
52 pthread_mutex_lock(&e.mutex);
53 e.tid = tid;
54 e.side = NOBODY;
55 pthread_mutex_unlock(&e.mutex);
57 } else {
58 engine_xboard = get_engine_value(&e.xboard_mode);
59 if (!engine_xboard && !get_engine_value(&e.thinking))
60 fprintf(stdout, "[%s]$ ", program_name);
62 /* Ctrl+D */
63 if (!fgets(cmd, MAX_STRING, stdin)) {
64 perform_cleanup();
65 exit(0);
68 if (!strcmp(cmd, "\n"))
69 continue;
71 if (parse_cmd(cmd))
72 continue;
74 /* check if we have received a move */
75 sscanf(cmd, "%s", move_buf);
77 /* parse according to the notation we are using */
78 if (get_engine_value(&e.san_notation) || !engine_xboard) {
79 if (!get_engine_value(&e.pondering))
80 move = parse_move_san(move_buf);
81 else {
82 move = 0;
83 for (i = 0; i < pm.count; i++)
84 if (strcmp(pm.sans[i], move_buf) == 0) {
85 move = pm.move[i];
86 break;
89 } else
90 move = parse_move_coord(move_buf);
92 if (!move)
93 fprintf(stdout, "Error (unknown command): %s\n", move_buf);
94 else {
95 /* OK, it is a legal move - make it */
97 if (return_ponder[0] && !strcmp(return_ponder, move_buf)) {
98 printf("[ Ponder Hit ]\n");
99 set_engine_value((int *)&e.pondering, 0);
100 set_engine_value((int *)&e.ponderhit, TRUE);
101 pthread_cond_signal(&cond_exit);
102 } else {
103 if (return_ponder[0]) {
104 printf("[ Ponder Fail :( ]\n");
106 /* stop pondering */
107 set_engine_value((int *)&e.pondering, 0);
108 set_engine_value((int *)&e.ponderhit, FALSE);
109 set_engine_value((int *)&e.stop_time, 0);
110 set_engine_value((int *)&e.max_stop_time, 0);
111 pthread_cond_signal(&cond_exit);
112 pthread_join(tid, NULL);
113 takeback();
116 make_move(move, FALSE);
117 set_engine_value(&e.side, brd.wtm);
124 static int
125 parse_cmd(char *cmd)
127 int val;
128 int inc;
129 char total_time[MAX_STRING];
130 char *filename;
131 pthread_t tid;
132 struct epd_info_t *ei;
133 struct moves_t moves;
135 /* start thinking */
136 if (!strncmp(cmd, "go", 2)) {
137 if (!get_engine_value(&e.thinking)) {
138 set_engine_value(&e.force_mode, FALSE);
139 set_engine_value(&e.side, brd.wtm);
141 /* display current board to console */
142 } else if (!strncmp(cmd, "board", 5))
143 print_board();
145 /* xboard send this command */
146 else if (!strncmp(cmd, "xboard", 6))
147 set_engine_value(&e.xboard_mode, TRUE);
148 /* stop thinking */
149 else if (!strncmp(cmd, "force", 5)) {
150 set_engine_value(&e.force_mode, TRUE);
151 set_engine_value(&e.side, NOBODY);
152 set_engine_value((int *)&e.stop_time, 0);
153 set_engine_value((int *)&e.max_stop_time, 0);
154 if (e.tid) {
155 val = pthread_join(e.tid, 0);
156 if (val)
157 fprintf(stderr, "Error occured: %s\n", strerror(val));
158 e.tid = 0;
160 /* move now command */
161 } else if (!strncmp(cmd, "?", 1)) {
162 set_engine_value((int *)&e.stop_time, 0);
163 set_engine_value((int *)&e.max_stop_time, 0);
164 /* the opponent is a computer */
165 } else if (!strncmp(cmd, "computer", 8))
166 set_engine_value(&e.play_computer, TRUE);
168 /* xboard support version protocol version 2. we should reply
169 by 'feature' command */
170 else if (!strncmp(cmd, "protover 2", 10)) {
171 set_engine_value(&e.san_notation, TRUE);
172 init_protover_2();
174 /* start new game */
175 } else if (!strncmp(cmd, "new", 3)) {
176 new_game();
177 set_engine_value(&e.play_computer, FALSE);
178 set_engine_value(&e.force_mode, FALSE);
179 set_engine_value(&e.max_depth, MAX_PLY);
180 set_engine_value(&e.side, BLACK);
181 /* display thinking */
182 } else if (!strncmp(cmd, "post", 4))
183 set_engine_value(&e.post_mode, TRUE);
184 else if (!strncmp(cmd, "easy", 4))
185 set_engine_value(&e.ponder_allowed, FALSE);
186 else if (!strncmp(cmd, "hard", 4))
187 set_engine_value(&e.ponder_allowed, TRUE);
188 /* do not display thinking */
189 else if (!strncmp(cmd, "nopost", 6))
190 set_engine_value(&e.post_mode, FALSE);
192 /* time remaining for the engine */
193 else if (sscanf(cmd, "time %d", &val) == 1) {
194 set_engine_value(&e.max_time, val / \
195 get_engine_value(&e.time_div));
196 set_engine_value(&e.max_depth, MAX_PLY);
197 set_engine_value(&e.fixed_time, FALSE);
198 pthread_cond_signal(&cond_exit);
200 } else if (sscanf(cmd, "otim %d", &val) == 1) {
201 /* handle but skip this */
202 } else if (sscanf(cmd, "st %d", &val) == 1) {
203 set_engine_value(&e.max_time, val);
204 set_engine_value(&e.max_depth, MAX_PLY);
205 set_engine_value(&e.fixed_time, TRUE);
207 /* set search depth */
208 } else if (sscanf(cmd, "sd %d", &val) == 1) {
209 set_engine_value(&e.max_time, 100000);
210 set_engine_value(&e.max_depth, val);
211 } else if (sscanf(cmd, "level %d %s %d", &val, &total_time, &inc) == 3) {
212 set_engine_value(&e.inc_time, inc * 100);
213 /* we can't change some parameters while searching */
214 /* enable/disable NULL move pruning (CLI command) */
215 } else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "null on", 7))
216 e.null_pruning = TRUE;
217 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "null off", 8))
218 e.null_pruning = FALSE;
220 /* enable/disable Late Move Reductions (CLI command) */
221 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "lmr on", 6))
222 e.lmr = TRUE;
223 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "lmr off", 7))
224 e.lmr = FALSE;
226 /* enable/disable Delta Pruning (CLI command) */
227 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "delta on", 8))
228 e.delta_pruning = TRUE;
229 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "delta off", 9))
230 e.delta_pruning = FALSE;
232 /* enable/disable Futility Pruning (CLI command) */
233 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "futil on", 8))
234 e.futility_pruning = TRUE;
235 else if (!get_engine_value(&e.thinking) && !strncmp(cmd, "futil off", 9))
236 e.futility_pruning = FALSE;
238 else if (!strncmp(cmd, "draw", 4)) {
239 } else if (!strncmp(cmd, "epd", 3)) {
240 if (!get_engine_value(&e.thinking)) {
241 /* EPD - solve test positions */
242 ei = malloc(sizeof(struct epd_info_t));
243 filename = malloc(MAX_STRING);
245 sscanf(cmd, "epd %s %d %d %d", filename, &ei->think_time, \
246 &ei->max_tests, &ei->first_test);
248 ei->filename = filename;
249 pthread_create(&tid, 0, run_epd_test, ei);
251 /* setup board from FEN position */
252 } else if (!strncmp(cmd, "setboard", 8)) {
253 if (!setup_board(cmd + 9))
254 fprintf(stdout, "Invalid FEN position: %s\n", cmd + 9);
255 set_engine_value(&e.side, NOBODY);
257 /* print FEN to stdout */
258 } else if (!strncmp(cmd, "fen", 3))
259 fprintf(stdout, "%s\n", current_fen_position(cmd));
261 /* takeback last move */
262 else if (!strncmp(cmd, "undo", 4)) {
263 set_engine_value(&e.side, NOBODY);
264 if (game_history.count)
265 takeback();
267 /* exit engine */
268 } else if (!strncmp(cmd, "quit", 4)) {
269 perform_cleanup();
270 exit(0);
272 /* reply with 'pong' command */
273 } else if (sscanf(cmd, "ping %d", &val) == 1)
274 fprintf(stdout, "pong %d\n", val);
276 /* print possible moves to stdout */
277 else if (!strncmp(cmd, "moves", 5)) {
278 gen_legal_moves(&moves);
279 print_moves_san(&moves);
280 } else if (!strncmp(cmd, "eval", 4))
281 printf("eval = %d\n", evaluate(-MATE_VALUE, MATE_VALUE));
282 else
283 /* invalid command, maybe it is a move */
284 return FALSE;
286 return TRUE;
289 /* default xboard parameters */
290 static void
291 init_protover_2(void)
293 /* disable Unix signals SIGINT and SIGTERM and tell some of our
294 parameters */
295 fprintf(stdout, "feature myname \"%s\"\n" \
296 "feature san=1\n" \
297 "feature colors=0\n" \
298 "feature setboard=1\n" \
299 "feature sigint=0\n" \
300 "feature sigterm=0\n" \
301 "feature ping=1\n" \
302 "feature done=1\n", program_name);