src/game.c

changeset 33
866025982aa9
parent 32
8a0b85303ee8
child 34
c4d4b8a8f902
equal deleted inserted replaced
32:8a0b85303ee8 33:866025982aa9
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++) {
154 169
155 const size_t buflen = 8; 170 const size_t buflen = 8;
156 size_t bufpos = 0; 171 size_t bufpos = 0;
157 char movestr[buflen]; 172 char movestr[buflen];
158 173
159 int inputy = getmaxy(stdscr) - 6; 174 flushinp();
160 while (1) { 175 while (1) {
161 draw_time(gamestate, gameinfo); 176 if (timecontrol(gamestate, gameinfo)) {
177 return 1;
178 }
179
162 move(inputy, 0); 180 move(inputy, 0);
163 printw( 181 printw(
164 "Use chess notation to enter your move.\n" 182 "Use chess notation to enter your move.\n"
165 "Or type 'surr' to surrender or 'remis' to end with remis.\n\n" 183 "Or type 'surr' to surrender or 'remis' to end with remis.\n\n"
166 "Type your move: "); 184 "Type your move: ");
167 clrtoeol(); 185 clrtoeol();
168 refresh();
169 186
170 if (asyncgetnstr(movestr, &bufpos, buflen)) { 187 if (asyncgetnstr(movestr, &bufpos, buflen)) {
171 if (strncmp(movestr, "surr", buflen) == 0) { 188 if (strncmp(movestr, "surr", buflen) == 0) {
172 printw("%s surrendered!", 189 printw("%s surrendered!",
173 gamestate->mycolor==WHITE?"White":"Black"); 190 gamestate->mycolor==WHITE?"White":"Black");
208 } 225 }
209 } 226 }
210 } 227 }
211 } 228 }
212 229
213 static int sendmove(GameState *gamestate, int opponent) { 230 static int sendmove(GameState *gamestate, GameInfo *gameinfo, int opponent) {
214 231
215 const size_t buflen = 8; 232 const size_t buflen = 8;
233 size_t bufpos = 0;
216 char movestr[buflen]; 234 char movestr[buflen];
217 _Bool remisrejected = FALSE; 235 _Bool remisrejected = FALSE;
218 uint8_t code; 236 uint8_t code;
219 237
220 int inputy = getmaxy(stdscr) - 6; 238 flushinp();
221 while (1) { 239 while (1) {
240 if (timecontrol(gamestate, gameinfo)) {
241 net_send_code(opponent, NETCODE_TIMEOVER);
242 return 1;
243 }
244
222 move(inputy, 0); 245 move(inputy, 0);
223 if (remisrejected) { 246 if (remisrejected) {
224 printw( 247 printw(
225 "Use chess notation to enter your move.\n" 248 "Use chess notation to enter your move.\n"
226 "Remis offer rejected - type 'surr' to surrender. \n\n" 249 "Remis offer rejected - type 'surr' to surrender. \n\n"
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) {
359 }; 387 };
360 memcpy(gamestate->board, initboard, sizeof(Board)); 388 memcpy(gamestate->board, initboard, sizeof(Board));
361 } 389 }
362 390
363 void game_start_singlemachine(Settings *settings) { 391 void game_start_singlemachine(Settings *settings) {
392 inputy = getmaxy(stdscr) - 6;
393
364 GameState gamestate; 394 GameState gamestate;
365 memset(&gamestate, 0, sizeof(GameState)); 395 memset(&gamestate, 0, sizeof(GameState));
366 init_board(&gamestate); 396 init_board(&gamestate);
367 gamestate.mycolor = WHITE; 397 gamestate.mycolor = WHITE;
368 398
383 refresh(); 413 refresh();
384 getch(); 414 getch();
385 } 415 }
386 416
387 void game_start(Settings *settings, int opponent) { 417 void game_start(Settings *settings, int opponent) {
418 inputy = getmaxy(stdscr) - 6;
419
388 _Bool myturn = is_server(settings) == 420 _Bool myturn = is_server(settings) ==
389 (settings->gameinfo.servercolor == WHITE); 421 (settings->gameinfo.servercolor == WHITE);
390 422
391 // TODO: time limit
392 GameState gamestate; 423 GameState gamestate;
393 memset(&gamestate, 0, sizeof(GameState)); 424 memset(&gamestate, 0, sizeof(GameState));
394 init_board(&gamestate); 425 init_board(&gamestate);
395 gamestate.mycolor = myturn ? WHITE:BLACK; 426 gamestate.mycolor = myturn ? WHITE:BLACK;
396 427
397 _Bool running; 428 _Bool running;
398 do { 429 do {
399 clear(); 430 clear();
400 draw_board(&gamestate); 431 draw_board(&gamestate);
401 if (myturn) { 432 if (myturn) {
402 running = !sendmove(&gamestate, opponent); 433 running = !sendmove(&gamestate, &(settings->gameinfo), opponent);
403 } else { 434 } else {
404 running = !recvmove(&gamestate, opponent); 435 running = !recvmove(&gamestate, &(settings->gameinfo), opponent);
405 flushinp(); // flush any input the user hacked in while waiting
406 } 436 }
407 myturn ^= TRUE; 437 myturn ^= TRUE;
408 } while (running); 438 } while (running);
409 439
410 move(0,0); 440 move(0,0);
413 gamestate_cleanup(&gamestate); 443 gamestate_cleanup(&gamestate);
414 444
415 mvaddstr(getmaxy(stdscr)-1, 0, 445 mvaddstr(getmaxy(stdscr)-1, 0,
416 "Game has ended. Press any key to leave..."); 446 "Game has ended. Press any key to leave...");
417 refresh(); 447 refresh();
448 cbreak();
449 flushinp();
418 getch(); 450 getch();
419 } 451 }

mercurial