1 /*  DreamChess
2 **
3 **  DreamChess is the legal property of its developers, whose names are too
4 **  numerous to list here. Please refer to the AUTHORS.txt file distributed
5 **  with this source distribution.
6 **
7 **  This program is free software: you can redistribute it and/or modify
8 **  it under the terms of the GNU General Public License as published by
9 **  the Free Software Foundation, either version 3 of the License, or
10 **  (at your option) any later version.
11 **
12 **  This program is distributed in the hope that it will be useful,
13 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **  GNU General Public License for more details.
16 **
17 **  You should have received a copy of the GNU General Public License
18 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "board.h"
25 #include "commands.h"
26 #include "config.h"
27 #include "dreamer.h"
28 #include "e_comm.h"
29 #include "hashing.h"
30 #include "move.h"
31 #include "repetition.h"
32 #include "search.h"
33 #include "transposition.h"
34 
35 #ifdef _WIN32
36 
37 #include <windows.h>
38 #define drm_sleep(M) Sleep(M)
39 
40 #elif defined HAVE_USLEEP
41 
42 #include <unistd.h>
43 
44 #define drm_sleep(M) usleep((M)*1000)
45 
46 #else
47 
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 
drm_sleep(unsigned long usec)52 static void drm_sleep(unsigned long usec) {
53 	struct timeval tv;
54 
55 	tv.tv_sec = 0;
56 	tv.tv_usec = usec;
57 	select(0, 0, 0, 0, &tv);
58 }
59 
60 #endif
61 
62 static int start_time;
63 static state_t state;
64 
my_turn(state_t * state)65 int my_turn(state_t *state) {
66 	return (((state->mode == MODE_WHITE) && (state->board.current_player == SIDE_WHITE)) ||
67 			((state->mode == MODE_BLACK) && (state->board.current_player == SIDE_BLACK)));
68 }
69 
is_check(board_t * board,int ply)70 int is_check(board_t *board, int ply) {
71 	/* FIXME */
72 	board->current_player = OPPONENT(board->current_player);
73 	if (compute_legal_moves(board, ply) < 0) {
74 		/* We're in check. */
75 		board->current_player = OPPONENT(board->current_player);
76 		return 1;
77 	}
78 	board->current_player = OPPONENT(board->current_player);
79 	return 0;
80 }
81 
check_game_state(board_t * board,int ply)82 int check_game_state(board_t *board, int ply) {
83 	move_t move;
84 	int mate = STATE_MATE;
85 	compute_legal_moves(board, ply);
86 
87 	while ((move = move_next(board, ply)) != NO_MOVE) {
88 		bitboard_t en_passant = board->en_passant;
89 		int castle_flags = board->castle_flags;
90 		int fifty_moves = board->fifty_moves;
91 
92 		execute_move(board, move);
93 		board->current_player = OPPONENT(board->current_player);
94 		if (!is_check(board, ply + 1)) {
95 			mate = STATE_NORMAL;
96 			board->current_player = OPPONENT(board->current_player);
97 			unmake_move(board, move, en_passant, castle_flags, fifty_moves);
98 			break;
99 		}
100 		board->current_player = OPPONENT(board->current_player);
101 		unmake_move(board, move, en_passant, castle_flags, fifty_moves);
102 	}
103 	/* We're either stalemated or checkmated. */
104 	if (!is_check(board, ply) && (mate == STATE_MATE))
105 		mate = STATE_STALEMATE;
106 	if (is_check(board, ply) && (mate == STATE_NORMAL))
107 		mate = STATE_CHECK;
108 	return mate;
109 }
110 
get_option(int option)111 int get_option(int option) {
112 	return state.options & (1 << option);
113 }
114 
set_option(int option,int value)115 void set_option(int option, int value) {
116 	state.options &= ~(1 << option);
117 	state.options |= (value << option);
118 }
119 
check_game_end(state_t * state)120 void check_game_end(state_t *state) {
121 	board_t *board = &state->board;
122 	int res = check_game_state(board, 0);
123 
124 	switch (res) {
125 	case STATE_MATE:
126 		state->done = 1;
127 		if (board->current_player == SIDE_WHITE)
128 			e_comm_send("0-1 {Black mates}\n");
129 		else
130 			e_comm_send("1-0 {White mates}\n");
131 		return;
132 	case STATE_STALEMATE:
133 		state->done = 1;
134 		e_comm_send("1/2-1/2 {Stalemate}\n");
135 		return;
136 	case STATE_NORMAL:
137 		switch (is_draw(board)) {
138 		case 1:
139 			state->done = 1;
140 			e_comm_send("1/2-1/2 {Drawn by 3-fold repetition}\n");
141 			return;
142 		case 2:
143 			state->done = 1;
144 			e_comm_send("1/2-1/2 {Drawn by 50 move rule}\n");
145 			return;
146 		}
147 	}
148 }
149 
check_abort(int ply)150 int check_abort(int ply) {
151 	char *s;
152 
153 	if (!(state.flags & FLAG_PONDER) && (timer_get(&state.move_time) <= 0))
154 		return 1;
155 
156 	s = e_comm_poll();
157 	if (!s)
158 		return 0;
159 	return command_check_abort(&state, ply, s);
160 }
161 
do_move(state_t * state,move_t move)162 void do_move(state_t *state, move_t move) {
163 	state->moves++;
164 	state->undo_data = realloc(state->undo_data, sizeof(undo_data_t) * state->moves);
165 	state->undo_data[state->moves - 1].en_passant = state->board.en_passant;
166 	state->undo_data[state->moves - 1].castle_flags = state->board.castle_flags;
167 	state->undo_data[state->moves - 1].fifty_moves = state->board.fifty_moves;
168 	state->undo_data[state->moves - 1].move = move;
169 	execute_move(&state->board, move);
170 	repetition_add(&state->board, move);
171 }
172 
undo_move(state_t * state)173 void undo_move(state_t *state) {
174 	if (state->moves == 0)
175 		return;
176 
177 	state->moves--;
178 
179 	unmake_move(&state->board, state->undo_data[state->moves].move, state->undo_data[state->moves].en_passant,
180 				state->undo_data[state->moves].castle_flags, state->undo_data[state->moves].fifty_moves);
181 
182 	repetition_remove();
183 }
184 
set_start_time(void)185 static void set_start_time(void) {
186 	struct timeval tv;
187 
188 	gettimeofday(&tv, NULL);
189 
190 	start_time = tv.tv_sec;
191 }
192 
set_move_time(void)193 void set_move_time(void) {
194 	int safe_time = timer_get(&state.engine_time) - 1000;
195 
196 	timer_init(&state.move_time, 1);
197 
198 	if (safe_time > 0) {
199 		if (state.time.mps == 0)
200 			timer_set(&state.move_time, safe_time / 30 + state.time.inc);
201 		else {
202 			int moves_left = state.time.mps - (state.moves / 2) % state.time.mps;
203 			timer_set(&state.move_time, safe_time / moves_left + state.time.inc);
204 		}
205 	} else
206 		timer_set(&state.move_time, 0);
207 }
208 
get_time(void)209 int get_time(void) {
210 	struct timeval tv;
211 
212 	gettimeofday(&tv, NULL);
213 
214 	tv.tv_sec -= start_time;
215 
216 	return tv.tv_sec * 100 + tv.tv_usec / 10000;
217 }
218 
update_clock(state_t * state)219 static void update_clock(state_t *state) {
220 	int val;
221 
222 	if (state->time.mps == 0)
223 		return;
224 
225 	val = timer_get(&state->engine_time);
226 
227 	if ((((state->moves + 1) / 2) % state->time.mps) == 0)
228 		val += state->time.base;
229 
230 	val += state->time.inc;
231 
232 	timer_set(&state->engine_time, val);
233 }
234 
send_move(state_t * state,move_t move)235 void send_move(state_t *state, move_t move) {
236 	char *str = coord_move_str(move);
237 	do_move(state, move);
238 	e_comm_send("move %s\n", str);
239 	timer_stop(&state->move_time);
240 	update_clock(state);
241 	free(str);
242 	check_game_end(state);
243 }
244 
engine(void * data)245 int engine(void *data) {
246 	e_comm_init();
247 	set_start_time();
248 
249 	state.time.mps = 40;
250 	state.time.base = 5;
251 	state.time.inc = 0;
252 	set_option(OPTION_QUIESCE, 1);
253 	set_option(OPTION_PONDER, 0);
254 	set_option(OPTION_POST, 0);
255 
256 	command_handle(&state, "new");
257 
258 	while (state.mode != MODE_QUIT) {
259 		char *s;
260 		move_t move;
261 
262 		s = e_comm_poll();
263 
264 		if (!s)
265 			drm_sleep(10);
266 		else {
267 			command_handle(&state, s);
268 			free(s);
269 		}
270 
271 		if (state.mode != MODE_IDLE && state.mode != MODE_FORCE && !state.done) {
272 			if (my_turn(&state)) {
273 				state.flags = 0;
274 				set_move_time();
275 
276 				timer_start(&state.engine_time);
277 				move = find_best_move(&state);
278 
279 				if (state.flags & FLAG_NEW_GAME)
280 					command_handle(&state, "new");
281 				else if (MOVE_IS_REGULAR(move)) {
282 					send_move(&state, move);
283 					timer_stop(&state.engine_time);
284 					if (get_option(OPTION_PONDER))
285 						state.flags |= FLAG_PONDER;
286 				}
287 			} else if (state.flags & FLAG_PONDER) {
288 				move = ponder(&state);
289 
290 				if (state.flags & FLAG_NEW_GAME)
291 					command_handle(&state, "new");
292 				else if (!my_turn(&state)) {
293 					if (move != NO_MOVE) {
294 						/* We are done pondering, but opponent hasn't moved yet. */
295 						state.ponder_my_move = move;
296 						state.flags = 0;
297 					} else {
298 						/* Opponent made an illegal move, continue pondering. */
299 						if (get_option(OPTION_PONDER))
300 							state.flags |= FLAG_PONDER;
301 					}
302 				} else if (MOVE_IS_REGULAR(move)) {
303 					/* Opponent made the expected move. */
304 					send_move(&state, move);
305 					if (get_option(OPTION_PONDER))
306 						state.flags |= FLAG_PONDER;
307 				}
308 			}
309 		}
310 	}
311 
312 	transposition_exit();
313 	return 0;
314 }
315