33 #include <ncurses.h> |
33 #include <ncurses.h> |
34 #include <string.h> |
34 #include <string.h> |
35 #include <inttypes.h> |
35 #include <inttypes.h> |
36 |
36 |
37 static const uint8_t boardx = 10, boardy = 10; |
37 static const uint8_t boardx = 10, boardy = 10; |
38 |
38 static int inputy = 21; /* should be overridden on game startup */ |
39 static void draw_time(GameState *gamestate, GameInfo *gameinfo) { |
39 |
|
40 static int timecontrol(GameState *gamestate, GameInfo *gameinfo) { |
40 if (gameinfo->timecontrol) { |
41 if (gameinfo->timecontrol) { |
41 // TODO: correct time display |
42 uint16_t white = remaining_movetime(gameinfo, gamestate, WHITE); |
42 |
43 uint16_t black = remaining_movetime(gameinfo, gamestate, BLACK); |
43 uint16_t whitem = gameinfo->time / 60; |
|
44 uint16_t whites = gameinfo->time % 60; |
|
45 uint16_t blackm = gameinfo->time / 60; |
|
46 uint16_t blacks = gameinfo->time % 60; |
|
47 |
|
48 mvprintw(boardy+4, boardx-1, |
44 mvprintw(boardy+4, boardx-1, |
49 "White time: %4" PRIu16 ":%02" PRIu16, whitem, whites); |
45 "White time: %4" PRIu16 ":%02" PRIu16, |
|
46 white / 60, white % 60); |
50 mvprintw(boardy+5, boardx-1, |
47 mvprintw(boardy+5, boardx-1, |
51 "Black time: %4" PRIu16 ":%02" PRIu16, blackm, blacks); |
48 "Black time: %4" PRIu16 ":%02" PRIu16, |
52 } |
49 black / 60, black % 60); |
|
50 |
|
51 if (white == 0) { |
|
52 move(inputy, 0); |
|
53 printw("Time is over - Black wins!"); |
|
54 clrtobot(); |
|
55 refresh(); |
|
56 return 1; |
|
57 } |
|
58 if (black == 0) { |
|
59 move(inputy, 0); |
|
60 printw("Time is over - White wins!"); |
|
61 clrtobot(); |
|
62 refresh(); |
|
63 return 1; |
|
64 } |
|
65 } |
|
66 |
|
67 return 0; |
53 } |
68 } |
54 |
69 |
55 static void draw_board(GameState *gamestate) { |
70 static void draw_board(GameState *gamestate) { |
56 for (uint8_t y = 0 ; y < 8 ; y++) { |
71 for (uint8_t y = 0 ; y < 8 ; y++) { |
57 for (uint8_t x = 0 ; x < 8 ; x++) { |
72 for (uint8_t x = 0 ; x < 8 ; x++) { |
230 "Use chess notation to enter your move.\n" |
253 "Use chess notation to enter your move.\n" |
231 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n" |
254 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n" |
232 "Type your move: "); |
255 "Type your move: "); |
233 } |
256 } |
234 clrtoeol(); |
257 clrtoeol(); |
235 refresh(); |
258 |
236 getnstr(movestr, buflen); |
259 if (asyncgetnstr(movestr, &bufpos, buflen)) { |
237 |
260 if (strncmp(movestr, "surr", buflen) == 0) { |
238 if (strncmp(movestr, "surr", buflen) == 0) { |
261 printw("You surrendered!"); |
239 printw("You surrendered!"); |
262 clrtoeol(); |
240 clrtoeol(); |
|
241 refresh(); |
|
242 net_send_code(opponent, NETCODE_SURRENDER); |
|
243 return 1; |
|
244 } else if (strncmp(movestr, "remis", buflen) == 0) { |
|
245 if (!remisrejected) { |
|
246 net_send_code(opponent, NETCODE_REMIS); |
|
247 printw("Remis offer sent - waiting for acceptance..."); |
|
248 refresh(); |
263 refresh(); |
249 if (net_recieve_code(opponent) == NETCODE_ACCEPT) { |
264 net_send_code(opponent, NETCODE_SURRENDER); |
250 printw("\rRemis accepted!"); |
265 return 1; |
251 clrtoeol(); |
266 } else if (strncmp(movestr, "remis", buflen) == 0) { |
|
267 if (!remisrejected) { |
|
268 net_send_code(opponent, NETCODE_REMIS); |
|
269 printw("Remis offer sent - waiting for acceptance..."); |
252 refresh(); |
270 refresh(); |
253 return 1; |
271 if (net_recieve_code(opponent) == NETCODE_ACCEPT) { |
254 } else { |
272 printw("\rRemis accepted!"); |
255 remisrejected = TRUE; |
|
256 } |
|
257 } |
|
258 } else { |
|
259 Move move; |
|
260 int eval_result = eval_move(gamestate, movestr, &move); |
|
261 switch (eval_result) { |
|
262 case VALID_MOVE_SYNTAX: |
|
263 net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); |
|
264 code = net_recieve_code(opponent); |
|
265 move.check = code == NETCODE_CHECK; |
|
266 gamestate->checkmate = code == NETCODE_CHECKMATE; |
|
267 gamestate->stalemate = code == NETCODE_STALEMATE; |
|
268 if (code == NETCODE_DECLINE) { |
|
269 printw("Invalid move."); |
|
270 } else { |
|
271 apply_move(gamestate, &move); |
|
272 if (gamestate->checkmate) { |
|
273 printw("Checkmate!"); |
|
274 clrtoeol(); |
273 clrtoeol(); |
275 return 1; |
274 refresh(); |
276 } else if (gamestate->stalemate) { |
|
277 printw("Stalemate!"); |
|
278 clrtoeol(); |
|
279 return 1; |
275 return 1; |
280 } else { |
276 } else { |
281 return 0; |
277 remisrejected = TRUE; |
282 } |
278 } |
283 } |
279 } |
284 break; |
280 } else { |
285 default: |
281 Move move; |
286 eval_move_failed_msg(eval_result); |
282 int eval_result = eval_move(gamestate, movestr, &move); |
287 } |
283 switch (eval_result) { |
288 clrtoeol(); |
284 case VALID_MOVE_SYNTAX: |
289 } |
285 net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); |
290 } |
286 code = net_recieve_code(opponent); |
291 } |
287 move.check = code == NETCODE_CHECK; |
292 |
288 gamestate->checkmate = code == NETCODE_CHECKMATE; |
293 static int recvmove(GameState *gamestate, int opponent) { |
289 gamestate->stalemate = code == NETCODE_STALEMATE; |
294 |
290 if (code == NETCODE_DECLINE) { |
295 int inputy = getmaxy(stdscr) - 6; |
291 printw("Invalid move."); |
|
292 } else { |
|
293 apply_move(gamestate, &move); |
|
294 if (gamestate->checkmate) { |
|
295 printw("Checkmate!"); |
|
296 clrtoeol(); |
|
297 return 1; |
|
298 } else if (gamestate->stalemate) { |
|
299 printw("Stalemate!"); |
|
300 clrtoeol(); |
|
301 return 1; |
|
302 } else { |
|
303 return 0; |
|
304 } |
|
305 } |
|
306 break; |
|
307 default: |
|
308 eval_move_failed_msg(eval_result); |
|
309 } |
|
310 clrtoeol(); |
|
311 } |
|
312 } |
|
313 } |
|
314 } |
|
315 |
|
316 static int recvmove(GameState *gamestate, GameInfo *gameinfo, int opponent) { |
|
317 |
296 while (1) { |
318 while (1) { |
|
319 timecontrol(gamestate, gameinfo); |
|
320 |
297 move(inputy, 0); |
321 move(inputy, 0); |
298 printw("Awaiting opponent move..."); |
322 printw("Awaiting opponent move..."); |
299 clrtoeol(); |
323 clrtoeol(); |
300 refresh(); |
324 refresh(); |
301 |
325 |
302 // TODO: nonblocking |
326 // TODO: nonblocking |
303 uint32_t code = net_recieve_code(opponent); |
327 uint32_t code = net_recieve_code(opponent); |
304 |
328 |
305 Move move; |
329 Move move; |
306 switch (code) { |
330 switch (code) { |
307 case NETCODE_SURRENDER: |
331 case NETCODE_TIMEOVER: |
308 printw("\rYour opponent surrendered!"); |
332 printw("\rYour opponent's time ran out - you win!"); |
309 clrtoeol(); |
333 clrtoeol(); |
|
334 return 1; |
|
335 case NETCODE_SURRENDER: |
|
336 printw("\rYour opponent surrendered!"); |
|
337 clrtoeol(); |
|
338 return 1; |
|
339 case NETCODE_REMIS: |
|
340 if (prompt_yesno( |
|
341 "\rYour opponent offers remis - do you accept")) { |
|
342 printw("\rRemis accepted!"); |
|
343 clrtoeol(); |
|
344 net_send_code(opponent, NETCODE_ACCEPT); |
310 return 1; |
345 return 1; |
311 case NETCODE_REMIS: |
346 } else { |
312 if (prompt_yesno( |
347 net_send_code(opponent, NETCODE_DECLINE); |
313 "\rYour opponent offers remis - do you accept")) { |
348 } |
314 printw("\rRemis accepted!"); |
349 break; |
|
350 case NETCODE_MOVE: |
|
351 net_recieve_data(opponent, &move, sizeof(Move)); |
|
352 if (validate_move(gamestate, &move)) { |
|
353 apply_move(gamestate, &move); |
|
354 if (move.check) { |
|
355 net_send_code(opponent, NETCODE_CHECK); |
|
356 } else if (gamestate->checkmate) { |
|
357 net_send_code(opponent, NETCODE_CHECKMATE); |
|
358 printw("\rCheckmate!"); |
315 clrtoeol(); |
359 clrtoeol(); |
316 net_send_code(opponent, NETCODE_ACCEPT); |
360 return 1; |
|
361 } else if (gamestate->stalemate) { |
|
362 net_send_code(opponent, NETCODE_STALEMATE); |
|
363 printw("\rStalemate!"); |
|
364 clrtoeol(); |
317 return 1; |
365 return 1; |
318 } else { |
366 } else { |
319 net_send_code(opponent, NETCODE_DECLINE); |
367 net_send_code(opponent, NETCODE_ACCEPT); |
320 } |
368 } |
321 break; |
369 return 0; |
322 case NETCODE_MOVE: |
370 } else { |
323 net_recieve_data(opponent, &move, sizeof(Move)); |
371 net_send_code(opponent, NETCODE_DECLINE); |
324 if (validate_move(gamestate, &move)) { |
372 } |
325 apply_move(gamestate, &move); |
|
326 if (move.check) { |
|
327 net_send_code(opponent, NETCODE_CHECK); |
|
328 } else if (gamestate->checkmate) { |
|
329 net_send_code(opponent, NETCODE_CHECKMATE); |
|
330 printw("\rCheckmate!"); |
|
331 clrtoeol(); |
|
332 return 1; |
|
333 } else if (gamestate->stalemate) { |
|
334 net_send_code(opponent, NETCODE_STALEMATE); |
|
335 printw("\rStalemate!"); |
|
336 clrtoeol(); |
|
337 return 1; |
|
338 } else { |
|
339 net_send_code(opponent, NETCODE_ACCEPT); |
|
340 } |
|
341 return 0; |
|
342 } else { |
|
343 net_send_code(opponent, NETCODE_DECLINE); |
|
344 } |
|
345 } |
373 } |
346 } |
374 } |
347 } |
375 } |
348 |
376 |
349 static void init_board(GameState *gamestate) { |
377 static void init_board(GameState *gamestate) { |