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