src/game.c

changeset 122
e65d9b5e9324
parent 117
ee539a9691f0
equal deleted inserted replaced
121:53f714ac783d 122:e65d9b5e9324
183 static void save_pgn(GameState *gamestate, GameInfo *gameinfo) { 183 static void save_pgn(GameState *gamestate, GameInfo *gameinfo) {
184 bool export_comments = prompt_yesno("Export with comments"); 184 bool export_comments = prompt_yesno("Export with comments");
185 185
186 printw("\rFilename: "); 186 printw("\rFilename: ");
187 clrtoeol(); 187 clrtoeol();
188 refresh();
189 188
190 char filename[64]; 189 char filename[64];
191 int y = getcury(stdscr); 190 int y = getcury(stdscr);
192 if (getnstr(filename, 64) == OK && filename[0] != '\0') { 191 if (getnstr(filename, 64) == OK && filename[0] != '\0') {
193 move(y, 0); 192 move(y, 0);
224 "%s to move: ", curcolorstr); 223 "%s to move: ", curcolorstr);
225 clrtoeol(); 224 clrtoeol();
226 225
227 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) { 226 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) {
228 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) { 227 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) {
229 gamestate->resign = 1; 228 gamestate->resign = true;
230 printw("%s resigned!", curcolorstr);
231 clrtobot();
232 refresh();
233 return 1; 229 return 1;
234 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) { 230 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) {
235 gamestate->remis = 1; 231 gamestate->remis = true;
236 printw("Game ends remis.");
237 clrtobot();
238 refresh();
239 return 1; 232 return 1;
240 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) { 233 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) {
241 save_pgn(gamestate, gameinfo); 234 save_pgn(gamestate, gameinfo);
242 } else { 235 } else {
243 Move move; 236 Move move;
245 if (result == VALID_MOVE_SYNTAX) { 238 if (result == VALID_MOVE_SYNTAX) {
246 result = validate_move(gamestate, &move); 239 result = validate_move(gamestate, &move);
247 if (result == VALID_MOVE_SEMANTICS) { 240 if (result == VALID_MOVE_SEMANTICS) {
248 apply_move(gamestate, &move); 241 apply_move(gamestate, &move);
249 if (gamestate->checkmate) { 242 if (gamestate->checkmate) {
250 printw("Checkmate!");
251 clrtoeol();
252 return 1; 243 return 1;
253 } else if (gamestate->stalemate) { 244 } else if (gamestate->stalemate) {
254 printw("Stalemate!");
255 clrtoeol();
256 return 1; 245 return 1;
257 } else { 246 } else {
258 return 0; 247 return 0;
259 } 248 }
260 } else { 249 } else {
321 break; 310 break;
322 case NETCODE_TAUNT: 311 case NETCODE_TAUNT:
323 resign_suggested = true; 312 resign_suggested = true;
324 break; 313 break;
325 case NETCODE_RESIGN: 314 case NETCODE_RESIGN:
326 gamestate->resign = 1; 315 gamestate->resign = true;
327 printw("\rYour opponent resigned!");
328 clrtoeol();
329 return 1; 316 return 1;
330 case NETCODE_CONNLOST: 317 case NETCODE_CONNLOST:
331 printw("\rYour opponent has left the game."); 318 gamestate->ragequit = true;
332 clrtoeol();
333 return 1; 319 return 1;
334 case NETCODE_ERROR: 320 case NETCODE_ERROR:
335 printw("\rCannot perform asynchronous network IO"); 321 printw("\rCannot perform asynchronous network IO");
336 cbreak(); getch(); 322 cbreak(); getch();
337 exit(EXIT_FAILURE); 323 exit(EXIT_FAILURE);
345 /* read move */ 331 /* read move */
346 if (use_premove || asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) { 332 if (use_premove || asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) {
347 bool was_premove = use_premove; 333 bool was_premove = use_premove;
348 use_premove = false; 334 use_premove = false;
349 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) { 335 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) {
350 gamestate->resign = 1; 336 gamestate->resign = true;
351 printw("You resigned!");
352 clrtoeol();
353 refresh();
354 net_send_code(opponent, NETCODE_RESIGN); 337 net_send_code(opponent, NETCODE_RESIGN);
355 return 1; 338 return 1;
356 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) { 339 } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) {
357 save_pgn(gamestate, gameinfo); 340 save_pgn(gamestate, gameinfo);
358 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) { 341 } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) {
359 if (remis_suggested) { 342 if (remis_suggested) {
360 net_send_code(opponent, NETCODE_REMIS); 343 net_send_code(opponent, NETCODE_REMIS);
361 gamestate->remis = 1; 344 gamestate->remis = true;
362 printw("\rRemis accepted!");
363 clrtoeol();
364 refresh();
365 return 1; 345 return 1;
366 } if (!remis_rejected) { 346 } if (!remis_rejected) {
367 net_send_code(opponent, NETCODE_REMIS); 347 net_send_code(opponent, NETCODE_REMIS);
368 printw("Remis offer sent - waiting for acceptance..."); 348 printw("Remis offer sent - waiting for acceptance...");
369 refresh(); 349 refresh();
370 code = net_recieve_code(opponent); 350 code = net_recieve_code(opponent);
371 if (code == NETCODE_ACCEPT) { 351 if (code == NETCODE_ACCEPT) {
372 gamestate->remis = 1; 352 gamestate->remis = true;
373 printw("\rRemis accepted!");
374 clrtoeol();
375 refresh();
376 return 1; 353 return 1;
377 } else if (code == NETCODE_CONNLOST) { 354 } else if (code == NETCODE_CONNLOST) {
378 printw("\rYour opponent left the game."); 355 gamestate->ragequit = true;
379 clrtoeol();
380 refresh();
381 return 1; 356 return 1;
382 } else { 357 } else {
383 remis_rejected = true; 358 remis_rejected = true;
384 } 359 }
385 } 360 }
402 } else if (code == NETCODE_ACCEPT 377 } else if (code == NETCODE_ACCEPT
403 || code == NETCODE_CHECK 378 || code == NETCODE_CHECK
404 || code == NETCODE_CHECKMATE 379 || code == NETCODE_CHECKMATE
405 || code == NETCODE_STALEMATE) { 380 || code == NETCODE_STALEMATE) {
406 apply_move(gamestate, &move); 381 apply_move(gamestate, &move);
407 if (gamestate->checkmate) { 382 if (gamestate->checkmate || gamestate->stalemate) {
408 printw("Checkmate!");
409 clrtoeol();
410 return 1;
411 } else if (gamestate->stalemate) {
412 printw("Stalemate!");
413 clrtoeol();
414 return 1; 383 return 1;
415 } else { 384 } else {
416 return 0; 385 return 0;
417 } 386 }
418 } else if (code == NETCODE_CONNLOST) { 387 } else if (code == NETCODE_CONNLOST) {
466 refresh(); 435 refresh();
467 436
468 /* allow the player to prepare a move */ 437 /* allow the player to prepare a move */
469 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) { 438 if (asyncgetnstr(movestr, &bufpos, MOVESTR_BUFLEN)) {
470 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) { 439 if (strncmp(movestr, "resign", MOVESTR_BUFLEN) == 0) {
471 gamestate->resign = 1; 440 gamestate->resign = true;
472 printw("You resigned!");
473 clrtoeol();
474 refresh();
475 net_send_code(opponent, NETCODE_RESIGN); 441 net_send_code(opponent, NETCODE_RESIGN);
476 return 1; 442 return 1;
477 } else if (strncmp(movestr, "taunt", MOVESTR_BUFLEN) == 0) { 443 } else if (strncmp(movestr, "taunt", MOVESTR_BUFLEN) == 0) {
478 resign_suggested = true; 444 resign_suggested = true;
479 net_send_code(opponent, NETCODE_TAUNT); 445 net_send_code(opponent, NETCODE_TAUNT);
503 case NETCODE_TIMEOVER: 469 case NETCODE_TIMEOVER:
504 /* redraw the time control */ 470 /* redraw the time control */
505 timecontrol(gamestate, gameinfo); 471 timecontrol(gamestate, gameinfo);
506 return 1; 472 return 1;
507 case NETCODE_RESIGN: 473 case NETCODE_RESIGN:
508 gamestate->resign = 1; 474 gamestate->resign = true;
509 printw("\rYour opponent resigned!");
510 clrtoeol();
511 return 1; 475 return 1;
512 case NETCODE_CONNLOST: 476 case NETCODE_CONNLOST:
513 printw("\rYour opponent has left the game."); 477 gamestate->ragequit = true;
514 clrtoeol();
515 return 1; 478 return 1;
516 case NETCODE_REMIS: 479 case NETCODE_REMIS:
517 if (remis_suggested) { 480 if (remis_suggested) {
518 gamestate->remis = 1; 481 gamestate->remis = true;
519 printw("\rRemis accepted!");
520 clrtoeol();
521 return 1; 482 return 1;
522 } else { 483 } else {
523 if (prompt_yesno( 484 if (prompt_yesno(
524 "\rYour opponent offers remis - do you accept")) { 485 "\rYour opponent offers remis - do you accept")) {
525 gamestate->remis = 1; 486 gamestate->remis = true;
526 printw("\rRemis accepted!");
527 clrtoeol();
528 net_send_code(opponent, NETCODE_ACCEPT); 487 net_send_code(opponent, NETCODE_ACCEPT);
529 return 1; 488 return 1;
530 } else { 489 } else {
531 net_send_code(opponent, NETCODE_DECLINE); 490 net_send_code(opponent, NETCODE_DECLINE);
532 } 491 }
538 code = validate_move(gamestate, &move); 497 code = validate_move(gamestate, &move);
539 if (code == VALID_MOVE_SEMANTICS) { 498 if (code == VALID_MOVE_SEMANTICS) {
540 apply_move(gamestate, &move); 499 apply_move(gamestate, &move);
541 if (gamestate->checkmate) { 500 if (gamestate->checkmate) {
542 net_send_code(opponent, NETCODE_CHECKMATE); 501 net_send_code(opponent, NETCODE_CHECKMATE);
543 printw("\rCheckmate!");
544 clrtoeol();
545 return 1; 502 return 1;
546 } else if (gamestate->stalemate) { 503 } else if (gamestate->stalemate) {
547 net_send_code(opponent, NETCODE_STALEMATE); 504 net_send_code(opponent, NETCODE_STALEMATE);
548 printw("\rStalemate!");
549 clrtoeol();
550 return 1; 505 return 1;
551 } else if (move.check) { 506 } else if (move.check) {
552 net_send_code(opponent, NETCODE_CHECK); 507 net_send_code(opponent, NETCODE_CHECK);
553 } else { 508 } else {
554 net_send_code(opponent, NETCODE_ACCEPT); 509 net_send_code(opponent, NETCODE_ACCEPT);
573 } 528 }
574 } 529 }
575 } 530 }
576 531
577 void game_review(Settings* settings, GameState *gamestate) { 532 void game_review(Settings* settings, GameState *gamestate) {
533 const unsigned page_moves = 10;
578 GameInfo *gameinfo = &(settings->gameinfo); 534 GameInfo *gameinfo = &(settings->gameinfo);
579 535 GameState viewedstate = {0};
580 move(0,0); 536 unsigned viewedmove = gamestate->movecount;
581 draw_board(gamestate, WHITE, settings->unicode); 537 bool redraw = true;
582 538
583 mvaddstr(getmaxy(stdscr)-1, 0,
584 "Press 'q' to quit or 's' to save a PGN file...");
585 refresh();
586 flushinp();
587
588 noecho(); 539 noecho();
589 int c; 540 int c;
590 do { 541 do {
542 if (redraw) {
543 gamestate_cleanup(&viewedstate);
544 gamestate_at_move(gamestate, viewedmove, &viewedstate);
545
546 erase(); /* don't use clear() to avoid flickering */
547 draw_board(&viewedstate, WHITE, settings->unicode);
548 timecontrol(&viewedstate, gameinfo);
549
550 move(getmaxy(stdscr)-5, 0);
551 const char *curcolorstr =
552 gamestate->movecount % 2 == 0 ? "White" : "Black";
553 if (gamestate->resign) {
554 printw("%s resigned.\n", curcolorstr);
555 } else if (gamestate->remis) {
556 addstr("The game ended remis.\n");
557 } else if (gamestate->stalemate) {
558 addstr("The game ended in a stalemate.\n");
559 } else if (gamestate->checkmate) {
560 printw("%s has lost the game.\n", curcolorstr);
561 } else if (gamestate->ragequit) {
562 printw("Your opponent disconnected.\n");
563 }
564 addstr("\nPress 'q' to quit, 's' to save the position as PGN, or\n"
565 "arrow keys, home/end, page up/down to review the game.\n");
566 flushinp();
567 redraw = false;
568 }
591 c = getch(); 569 c = getch();
592 if (c == 's') { 570 if (c == 's') {
593 addch('\r'); 571 addch('\r');
594 echo(); 572 echo();
595 save_pgn(gamestate, gameinfo); 573 save_pgn(&viewedstate, gameinfo);
596 addstr(" Press 'q' to quit...");
597 noecho(); 574 noecho();
575 redraw = true;
576 } else if (c == KEY_UP || c == KEY_LEFT) {
577 if (viewedmove > 0) {
578 viewedmove--;
579 redraw = true;
580 }
581 } else if (c == KEY_DOWN || c == KEY_RIGHT) {
582 if (viewedmove < gamestate->movecount) {
583 viewedmove++;
584 redraw = true;
585 }
586 } else if (c == KEY_HOME) {
587 viewedmove = 0;
588 redraw = true;
589 } else if (c == KEY_END) {
590 viewedmove = gamestate->movecount;
591 redraw = true;
592 } else if (c == KEY_PPAGE) {
593 if (viewedmove > page_moves) {
594 viewedmove -= page_moves;
595 } else {
596 viewedmove = 0;
597 }
598 redraw = true;
599 } else if (c == KEY_NPAGE) {
600 viewedmove += page_moves;
601 if (viewedmove > gamestate->movecount) {
602 viewedmove = gamestate->movecount;
603 }
604 redraw = true;
598 } 605 }
599 } while (c != 'q'); 606 } while (c != 'q');
600 echo(); 607 echo();
601 608 gamestate_cleanup(&viewedstate);
602 gamestate_cleanup(gamestate);
603 } 609 }
604 610
605 void game_play_singlemachine(Settings *settings) { 611 void game_play_singlemachine(Settings *settings) {
606 inputy = getmaxy(stdscr) - 6; 612 inputy = getmaxy(stdscr) - 6;
607 613
640 &(settings->gameinfo), curcol); 646 &(settings->gameinfo), curcol);
641 curcol = opponent_color(curcol); 647 curcol = opponent_color(curcol);
642 } while (running); 648 } while (running);
643 649
644 game_review(settings, &gamestate); 650 game_review(settings, &gamestate);
651 gamestate_cleanup(&gamestate);
645 } 652 }
646 653
647 void game_play(Settings *settings, GameState *gamestate, int opponent) { 654 void game_play(Settings *settings, GameState *gamestate, int opponent) {
648 inputy = getmaxy(stdscr) - 6; 655 inputy = getmaxy(stdscr) - 6;
649 656

mercurial