src/game.c

changeset 113
5f58df30d422
parent 110
e2bb03494d46
child 114
12df1b7c792f
equal deleted inserted replaced
112:6220074cb760 113:5f58df30d422
270 static int sendmove(GameState *gamestate, GameInfo *gameinfo, 270 static int sendmove(GameState *gamestate, GameInfo *gameinfo,
271 int opponent, uint8_t mycolor) { 271 int opponent, uint8_t mycolor) {
272 272
273 size_t bufpos = 0; 273 size_t bufpos = 0;
274 char movestr[MOVESTR_BUFLEN]; 274 char movestr[MOVESTR_BUFLEN];
275 bool remisrejected = false; 275 bool remis_rejected = false;
276 bool remis_suggested = false;
277 bool use_premove = false;
276 uint8_t code; 278 uint8_t code;
279
280 if (*gamestate->premove) {
281 use_premove = true;
282 const unsigned mlen = sizeof(gamestate->premove);
283 strncpy(movestr, gamestate->premove, mlen);
284 movestr[mlen] = '\0';
285 memset(gamestate->premove, 0, mlen);
286 }
277 287
278 flushinp(); 288 flushinp();
279 while (1) { 289 while (1) {
280 if (timecontrol(gamestate, gameinfo)) { 290 if (timecontrol(gamestate, gameinfo)) {
281 net_send_code(opponent, NETCODE_TIMEOVER); 291 net_send_code(opponent, NETCODE_TIMEOVER);
282 return 1; 292 return 1;
283 } 293 }
284 294
285 move(inputy, 0); 295 move(inputy, 0);
286 if (remisrejected) { 296 printw("Use chess notation to enter your move.\n");
287 printw( 297 if (remis_suggested) {
288 "Use chess notation to enter your move.\n" 298 printw("The opponent offers remis. Also type remis to accept.\n\n");
289 "Remis offer rejected \n\n" 299 } else if (remis_rejected) {
290 "Type your move: "); 300 printw("Remis offer rejected. \n\n");
291 } else { 301 } else {
292 printw( 302 printw("Or use a command: remis, resign, savepgn \n\n");
293 "Use chess notation to enter your move.\n" 303 }
294 "Or use a command: remis, resign, savepgn\n\n" 304 printw("Type your move: ");
295 "Type your move: ");
296 }
297 clrtoeol(); 305 clrtoeol();
298 306
299 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) { 307 /* check if the opponent sent us something */
308 code = net_recieve_code_async(opponent);
309 switch (code) {
310 case NETCODE_REMIS:
311 remis_suggested = true;
312 break;
313 case NETCODE_RESIGN:
314 gamestate->resign = 1;
315 printw("\rYour opponent resigned!");
316 clrtoeol();
317 return 1;
318 case NETCODE_CONNLOST:
319 printw("\rYour opponent has left the game.");
320 clrtoeol();
321 return 1;
322 case NETCODE_ERROR:
323 printw("\rCannot perform asynchronous network IO");
324 cbreak(); getch();
325 exit(EXIT_FAILURE);
326 case NETCODE_AGAIN:
327 /* try again */
328 break;
329 default:
330 printw("\nThe opponent sent an invalid network pacakge.");
331 }
332
333 /* read move */
334 if (use_premove || asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) {
335 use_premove = false;
300 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) { 336 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) {
301 gamestate->resign = 1; 337 gamestate->resign = 1;
302 printw("You resigned!"); 338 printw("You resigned!");
303 clrtoeol(); 339 clrtoeol();
304 refresh(); 340 refresh();
305 net_send_code(opponent, NETCODE_RESIGN); 341 net_send_code(opponent, NETCODE_RESIGN);
306 return 1; 342 return 1;
307 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) { 343 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) {
308 save_pgn(gamestate, gameinfo); 344 save_pgn(gamestate, gameinfo);
309 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) { 345 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) {
310 if (!remisrejected) { 346 if (remis_suggested) {
347 net_send_code(opponent, NETCODE_REMIS);
348 gamestate->remis = 1;
349 printw("\rRemis accepted!");
350 clrtoeol();
351 refresh();
352 return 1;
353 } if (!remis_rejected) {
311 net_send_code(opponent, NETCODE_REMIS); 354 net_send_code(opponent, NETCODE_REMIS);
312 printw("Remis offer sent - waiting for acceptance..."); 355 printw("Remis offer sent - waiting for acceptance...");
313 refresh(); 356 refresh();
314 code = net_recieve_code(opponent); 357 code = net_recieve_code(opponent);
315 if (code == NETCODE_ACCEPT) { 358 if (code == NETCODE_ACCEPT) {
322 printw("\rYour opponent left the game."); 365 printw("\rYour opponent left the game.");
323 clrtoeol(); 366 clrtoeol();
324 refresh(); 367 refresh();
325 return 1; 368 return 1;
326 } else { 369 } else {
327 remisrejected = true; 370 remis_rejected = true;
328 } 371 }
329 } 372 }
330 } else { 373 } else {
331 Move move; 374 Move move;
332 int eval_result = eval_move(gamestate, movestr, &move, mycolor); 375 int eval_result = eval_move(gamestate, movestr, &move, mycolor);
373 } 416 }
374 } 417 }
375 } 418 }
376 } 419 }
377 420
378 static int recvmove(GameState *gamestate, GameInfo *gameinfo, int opponent) { 421 static int recvmove(GameState *gamestate, GameInfo *gameinfo,
379 422 int opponent, uint8_t mycolor) {
380 struct timeval timeout; 423 memset(gamestate->premove, 0, sizeof(gamestate->premove));
424
425 size_t bufpos = 0;
426 char movestr[MOVESTR_BUFLEN];
427 bool remis_suggested = false;
381 while (1) { 428 while (1) {
382 timecontrol(gamestate, gameinfo); 429 timecontrol(gamestate, gameinfo);
383 430
384 move(inputy, 0); 431 move(inputy, 0);
385 printw("Awaiting opponent move..."); 432 printw("Awaiting opponent move. Use chess notation to prepare a move.\n");
433 if (*gamestate->premove) {
434 printw("Current pre-move: %s \n\n",
435 gamestate->premove);
436 } else if (remis_suggested) {
437 printw("Suggested remis. \n\n");
438 } else {
439 printw("Or use a command: remis, resign, savepgn\n\n");
440 }
441 printw("Prepare your next move: ");
386 clrtoeol(); 442 clrtoeol();
387 refresh(); 443 refresh();
388 444
389 fd_set readfds; 445 /* allow the player to prepare a move */
390 446 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) {
391 FD_ZERO(&readfds); 447 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) {
392 FD_SET(opponent, &readfds); 448 gamestate->resign = 1;
393 timeout.tv_sec = 0; 449 printw("You resigned!");
394 timeout.tv_usec = 100000; 450 clrtoeol();
395 451 refresh();
396 // TODO: allow commands while waiting (e.g. resign, offer draw) 452 net_send_code(opponent, NETCODE_RESIGN);
397
398 int result = select(opponent+1, &readfds, NULL, NULL, &timeout);
399 if (result == -1) {
400 printw("\rCannot perform asynchronous network IO");
401 cbreak(); getch();
402 exit(EXIT_FAILURE);
403 }
404 if (result > 0) {
405 uint8_t code = net_recieve_code(opponent);
406
407 Move move;
408 switch (code) {
409 case NETCODE_TIMEOVER:
410 /* redraw the time control */
411 timecontrol(gamestate, gameinfo);
412 return 1; 453 return 1;
413 case NETCODE_RESIGN: 454 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) {
414 gamestate->resign = 1; 455 remis_suggested = true;
415 printw("\rYour opponent resigned!"); 456 net_send_code(opponent, NETCODE_REMIS);
457 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) {
458 save_pgn(gamestate, gameinfo);
459 } else if (movestr[0] == 0) {
460 memset(gamestate->premove, 0, sizeof(gamestate->premove));
461 } else {
462 Move move;
463 int res = eval_move(gamestate, movestr, &move, mycolor);
464 if (res == VALID_MOVE_SYNTAX) {
465 strncpy(gamestate->premove, movestr, 8);
466 memset(movestr, 0, MOVESTR_BUFLEN);
467 bufpos = 0;
468 clrtobot();
469 } else {
470 eval_move_failed_msg(res);
471 }
472 }
473 }
474
475 /* read opponent's move */
476 uint8_t code = net_recieve_code_async(opponent);
477 switch (code) {
478 case NETCODE_TIMEOVER:
479 /* redraw the time control */
480 timecontrol(gamestate, gameinfo);
481 return 1;
482 case NETCODE_RESIGN:
483 gamestate->resign = 1;
484 printw("\rYour opponent resigned!");
485 clrtoeol();
486 return 1;
487 case NETCODE_CONNLOST:
488 printw("\rYour opponent has left the game.");
489 clrtoeol();
490 return 1;
491 case NETCODE_REMIS:
492 if (remis_suggested) {
493 gamestate->remis = 1;
494 printw("\rRemis accepted!");
416 clrtoeol(); 495 clrtoeol();
417 return 1; 496 return 1;
418 case NETCODE_CONNLOST: 497 } else {
419 printw("\rYour opponent has left the game.");
420 clrtoeol();
421 return 1;
422 case NETCODE_REMIS:
423 if (prompt_yesno( 498 if (prompt_yesno(
424 "\rYour opponent offers remis - do you accept")) { 499 "\rYour opponent offers remis - do you accept")) {
425 gamestate->remis = 1; 500 gamestate->remis = 1;
426 printw("\rRemis accepted!"); 501 printw("\rRemis accepted!");
427 clrtoeol(); 502 clrtoeol();
428 net_send_code(opponent, NETCODE_ACCEPT); 503 net_send_code(opponent, NETCODE_ACCEPT);
429 return 1; 504 return 1;
430 } else { 505 } else {
431 net_send_code(opponent, NETCODE_DECLINE); 506 net_send_code(opponent, NETCODE_DECLINE);
432 } 507 }
433 break; 508 }
434 case NETCODE_MOVE: 509 break;
435 net_recieve_data(opponent, &move, sizeof(Move)); 510 case NETCODE_MOVE: {
436 code = validate_move(gamestate, &move); 511 Move move;
437 if (code == VALID_MOVE_SEMANTICS) { 512 net_recieve_data(opponent, &move, sizeof(Move));
438 apply_move(gamestate, &move); 513 code = validate_move(gamestate, &move);
439 if (gamestate->checkmate) { 514 if (code == VALID_MOVE_SEMANTICS) {
440 net_send_code(opponent, NETCODE_CHECKMATE); 515 apply_move(gamestate, &move);
441 printw("\rCheckmate!"); 516 if (gamestate->checkmate) {
442 clrtoeol(); 517 net_send_code(opponent, NETCODE_CHECKMATE);
443 return 1; 518 printw("\rCheckmate!");
444 } else if (gamestate->stalemate) { 519 clrtoeol();
445 net_send_code(opponent, NETCODE_STALEMATE); 520 return 1;
446 printw("\rStalemate!"); 521 } else if (gamestate->stalemate) {
447 clrtoeol(); 522 net_send_code(opponent, NETCODE_STALEMATE);
448 return 1; 523 printw("\rStalemate!");
449 } else if (move.check) { 524 clrtoeol();
450 net_send_code(opponent, NETCODE_CHECK); 525 return 1;
451 } else { 526 } else if (move.check) {
452 net_send_code(opponent, NETCODE_ACCEPT); 527 net_send_code(opponent, NETCODE_CHECK);
453 }
454 return 0;
455 } else { 528 } else {
456 uint32_t reason = htonl(code); 529 net_send_code(opponent, NETCODE_ACCEPT);
457 net_send_data(opponent, NETCODE_DECLINE,
458 &reason, sizeof(uint32_t));
459 } 530 }
460 break; 531 return 0;
461 default: 532 } else {
462 printw("\nInvalid network request."); 533 uint32_t reason = htonl(code);
463 } 534 net_send_data(opponent, NETCODE_DECLINE,
535 &reason, sizeof(uint32_t));
536 }
537 break;
538 }
539 case NETCODE_ERROR:
540 printw("\rCannot perform asynchronous network IO");
541 cbreak(); getch();
542 exit(EXIT_FAILURE);
543 case NETCODE_AGAIN:
544 /* try again */
545 break;
546 default:
547 printw("\nInvalid network request.");
464 } 548 }
465 } 549 }
466 } 550 }
467 551
468 void game_review(Settings* settings, GameState *gamestate) { 552 void game_review(Settings* settings, GameState *gamestate) {
552 draw_board(gamestate, mycolor, settings->unicode); 636 draw_board(gamestate, mycolor, settings->unicode);
553 if (myturn) { 637 if (myturn) {
554 running = !sendmove(gamestate, &(settings->gameinfo), 638 running = !sendmove(gamestate, &(settings->gameinfo),
555 opponent, mycolor); 639 opponent, mycolor);
556 } else { 640 } else {
557 running = !recvmove(gamestate, &(settings->gameinfo), opponent); 641 running = !recvmove(gamestate, &(settings->gameinfo),
642 opponent, mycolor);
558 } 643 }
559 myturn ^= true; 644 myturn ^= true;
560 } while (running); 645 } while (running);
561 } 646 }
562 647

mercurial