added support for game continuation over network + fixed major bug in checkmate anticipation when the king is attacked diagonally

Mon, 16 Jun 2014 15:41:06 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 16 Jun 2014 15:41:06 +0200
changeset 51
84f2e380a434
parent 50
41017d0a72c5
child 52
26707039d5a6

added support for game continuation over network + fixed major bug in checkmate anticipation when the king is attacked diagonally

src/chess/pgn.h file | annotate | diff | comparison | revisions
src/chess/rules.c file | annotate | diff | comparison | revisions
src/client.c file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
src/game.h file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/network.h file | annotate | diff | comparison | revisions
src/server.c file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
     1.1 --- a/src/chess/pgn.h	Mon Jun 16 13:45:31 2014 +0200
     1.2 +++ b/src/chess/pgn.h	Mon Jun 16 15:41:06 2014 +0200
     1.3 @@ -41,7 +41,6 @@
     1.4  int read_pgn(FILE *stream, GameState *gamestate, GameInfo *gameinfo);
     1.5  size_t write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo);
     1.6  
     1.7 -
     1.8  #ifdef	__cplusplus
     1.9  }
    1.10  #endif
     2.1 --- a/src/chess/rules.c	Mon Jun 16 13:45:31 2014 +0200
     2.2 +++ b/src/chess/rules.c	Mon Jun 16 15:41:06 2014 +0200
     2.3 @@ -40,7 +40,7 @@
     2.4          *lastmovecopy = *(simulation.lastmove);
     2.5          simulation.movelist = simulation.lastmove = lastmovecopy;
     2.6      }
     2.7 -        
     2.8 +
     2.9      return simulation;
    2.10  }
    2.11  
    2.12 @@ -421,13 +421,13 @@
    2.13                      }
    2.14                  } else {
    2.15                      /* bishop aspect */
    2.16 -                    int dr = move->torow > move->fromrow ? 1 : -1;
    2.17 -                    int df = move->tofile > move->fromfile ? 1 : -1;
    2.18 +                    int dr = threat->torow > threat->fromrow ? 1 : -1;
    2.19 +                    int df = threat->tofile > threat->fromfile ? 1 : -1;
    2.20  
    2.21 -                    uint8_t row = move->fromrow;
    2.22 -                    uint8_t file = move->fromfile;
    2.23 -                    while (!canescape && file != move->tofile - df
    2.24 -                        && row != move->torow - dr) {
    2.25 +                    uint8_t row = threat->fromrow;
    2.26 +                    uint8_t file = threat->fromfile;
    2.27 +                    while (!canescape && file != threat->tofile - df
    2.28 +                        && row != threat->torow - dr) {
    2.29                          row += dr;
    2.30                          file += df;
    2.31                          canescape |= is_protected(&simulation, row, file,
     3.1 --- a/src/client.c	Mon Jun 16 13:45:31 2014 +0200
     3.2 +++ b/src/client.c	Mon Jun 16 15:41:06 2014 +0200
     3.3 @@ -73,9 +73,10 @@
     3.4          return EXIT_FAILURE;
     3.5      }
     3.6  
     3.7 -    if (net_recieve_code(server.fd) == NETCODE_GAMEINFO) {
     3.8 -        net_recieve_data(server.fd, &(settings->gameinfo),
     3.9 -            sizeof(settings->gameinfo));
    3.10 +    uint8_t code = net_recieve_code(server.fd);
    3.11 +    if (code == NETCODE_GAMEINFO) {
    3.12 +        // Start new game
    3.13 +        net_recieve_data(server.fd, &(settings->gameinfo), sizeof(GameInfo));
    3.14          dump_gameinfo(&(settings->gameinfo));
    3.15          if (prompt_yesno("Accept challenge")) {
    3.16              net_send_code(server.fd, NETCODE_ACCEPT);
    3.17 @@ -83,6 +84,28 @@
    3.18          } else {
    3.19              net_send_code(server.fd, NETCODE_DECLINE);
    3.20          }
    3.21 +    } else if (code == NETCODE_PGNDATA) {
    3.22 +        net_recieve_data(server.fd, &(settings->gameinfo), sizeof(GameInfo));
    3.23 +        dump_gameinfo(&(settings->gameinfo));
    3.24 +        uint16_t mc;
    3.25 +        net_recieve_data(server.fd, &mc, sizeof(mc));
    3.26 +        Move *moves = calloc(mc, sizeof(Move));
    3.27 +        net_recieve_data(server.fd, moves, mc*sizeof(Move));
    3.28 +        GameState continuegame;
    3.29 +        gamestate_init(&continuegame);
    3.30 +        for (size_t i = 0 ; i < mc ; i++) {
    3.31 +            apply_move(&continuegame, &(moves[i]));
    3.32 +        }
    3.33 +        free(moves);
    3.34 +        addch('\n');
    3.35 +        dump_moveinfo(&continuegame);
    3.36 +        if (prompt_yesno(
    3.37 +                "\n\nServer wants to continue a game. Accept challenge")) {
    3.38 +            net_send_code(server.fd, NETCODE_ACCEPT);
    3.39 +            game_continue(settings, server.fd, &continuegame);
    3.40 +        } else {
    3.41 +            net_send_code(server.fd, NETCODE_DECLINE);
    3.42 +        }
    3.43      } else {
    3.44          addstr("Server sent invalid gameinfo.");
    3.45          net_destroy(&server);
     4.1 --- a/src/game.c	Mon Jun 16 13:45:31 2014 +0200
     4.2 +++ b/src/game.c	Mon Jun 16 15:41:06 2014 +0200
     4.3 @@ -174,7 +174,7 @@
     4.4      
     4.5      char filename[64];
     4.6      int y = getcury(stdscr);
     4.7 -    if (getnstr(filename, 64) == OK) {
     4.8 +    if (getnstr(filename, 64) == OK && filename[0] != '\0') {
     4.9          move(y, 0);
    4.10          FILE *file = fopen(filename, "w");
    4.11          if (file) {
    4.12 @@ -322,8 +322,7 @@
    4.13                  int eval_result = eval_move(gamestate, movestr, &move, mycolor);
    4.14                  switch (eval_result) {
    4.15                  case VALID_MOVE_SYNTAX:
    4.16 -                    net_send_data(opponent, NETCODE_MOVE, &move,
    4.17 -                        sizeof(Move)-8);
    4.18 +                    net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move));
    4.19                      code = net_recieve_code(opponent);
    4.20                      move.check = code == NETCODE_CHECK ||
    4.21                          code == NETCODE_CHECKMATE;
    4.22 @@ -423,13 +422,11 @@
    4.23                  }
    4.24                  break;
    4.25              case NETCODE_MOVE:
    4.26 -                net_recieve_data(opponent, &move, sizeof(Move)-8);
    4.27 +                net_recieve_data(opponent, &move, sizeof(Move));
    4.28                  code = validate_move(gamestate, &move);
    4.29                  if (code == VALID_MOVE_SEMANTICS) {
    4.30                      apply_move(gamestate, &move);
    4.31 -                    if (move.check) {
    4.32 -                        net_send_code(opponent, NETCODE_CHECK);
    4.33 -                    } else if (gamestate->checkmate) {
    4.34 +                    if (gamestate->checkmate) {
    4.35                          net_send_code(opponent, NETCODE_CHECKMATE);
    4.36                          printw("\rCheckmate!");
    4.37                          clrtoeol();
    4.38 @@ -439,6 +436,8 @@
    4.39                          printw("\rStalemate!");
    4.40                          clrtoeol();
    4.41                          return 1;
    4.42 +                    } else if (move.check) {
    4.43 +                        net_send_code(opponent, NETCODE_CHECK);
    4.44                      } else {
    4.45                          net_send_code(opponent, NETCODE_ACCEPT);
    4.46                      }
    4.47 @@ -523,28 +522,34 @@
    4.48      post_game(&gamestate, &(settings->gameinfo));
    4.49  }
    4.50  
    4.51 -void game_start(Settings *settings, int opponent) {
    4.52 +void game_continue(Settings *settings, int opponent, GameState *gamestate) {
    4.53      inputy = getmaxy(stdscr) - 6;
    4.54      
    4.55 -    _Bool myturn = is_server(settings) ==
    4.56 -        (settings->gameinfo.servercolor == WHITE);
    4.57 -    uint8_t mycolor = myturn ? WHITE : BLACK;
    4.58 +    uint8_t mycolor = is_server(settings) ? settings->gameinfo.servercolor :
    4.59 +        opponent_color(settings->gameinfo.servercolor);
    4.60      
    4.61 -    GameState gamestate;
    4.62 -    gamestate_init(&gamestate);
    4.63 +    _Bool myturn = (gamestate->lastmove ?
    4.64 +        (gamestate->lastmove->move.piece & COLOR_MASK) : WHITE) != mycolor;
    4.65      
    4.66      _Bool running;
    4.67      do {
    4.68          clear();
    4.69 -        draw_board(&gamestate, mycolor);
    4.70 +        draw_board(gamestate, mycolor);
    4.71          if (myturn) {
    4.72 -            running = !sendmove(&gamestate, &(settings->gameinfo),
    4.73 +            running = !sendmove(gamestate, &(settings->gameinfo),
    4.74                  opponent, mycolor);
    4.75          } else {
    4.76 -            running = !recvmove(&gamestate, &(settings->gameinfo), opponent);
    4.77 +            running = !recvmove(gamestate, &(settings->gameinfo), opponent);
    4.78          }
    4.79          myturn ^= TRUE;
    4.80      }  while (running);
    4.81      
    4.82 -    post_game(&gamestate, &(settings->gameinfo));
    4.83 +    post_game(gamestate, &(settings->gameinfo));
    4.84  }
    4.85 +
    4.86 +void game_start(Settings *settings, int opponent) {
    4.87 +    GameState gamestate;
    4.88 +    gamestate_init(&gamestate);
    4.89 +    
    4.90 +    game_continue(settings, opponent, &gamestate);
    4.91 +}
     5.1 --- a/src/game.h	Mon Jun 16 13:45:31 2014 +0200
     5.2 +++ b/src/game.h	Mon Jun 16 15:41:06 2014 +0200
     5.3 @@ -38,6 +38,7 @@
     5.4  #endif
     5.5  
     5.6  void game_start(Settings *settings, int opponent);
     5.7 +void game_continue(Settings *settings, int opponent, GameState *gamestate);
     5.8  void game_start_singlemachine(Settings *settings);
     5.9  
    5.10  #ifdef	__cplusplus
     6.1 --- a/src/main.c	Mon Jun 16 13:45:31 2014 +0200
     6.2 +++ b/src/main.c	Mon Jun 16 15:41:06 2014 +0200
     6.3 @@ -116,12 +116,6 @@
     6.4              fprintf(stderr, "The options -c and -S are mutually exclusive\n");
     6.5              return 1;
     6.6          }
     6.7 -        // TODO: implement
     6.8 -        if (!settings->singlemachine) {
     6.9 -            fprintf(stderr, "Game continuation currently not supported for "
    6.10 -                "network games.\n");
    6.11 -            return 1;
    6.12 -        }
    6.13      }
    6.14      
    6.15      return 0;
    6.16 @@ -157,6 +151,24 @@
    6.17      refresh();
    6.18  }
    6.19  
    6.20 +void dump_moveinfo(GameState *gamestate) {
    6.21 +    int i = 1;
    6.22 +    for (MoveList *movelist = gamestate->movelist ;
    6.23 +        movelist ; movelist = movelist->next) {        
    6.24 +        if (++i % 2 == 0) {
    6.25 +            printw("%d. %s", i/2, movelist->move.string);
    6.26 +        } else {
    6.27 +            printw(" %s", movelist->move.string);
    6.28 +        }
    6.29 +        if (i % 20)  {
    6.30 +            addch(' ');
    6.31 +        } else {
    6.32 +            addch('\n');
    6.33 +        }
    6.34 +    }
    6.35 +    refresh();
    6.36 +}
    6.37 +
    6.38  void leavescr() {
    6.39      endwin();
    6.40  }
     7.1 --- a/src/network.h	Mon Jun 16 13:45:31 2014 +0200
     7.2 +++ b/src/network.h	Mon Jun 16 15:41:06 2014 +0200
     7.3 @@ -40,6 +40,7 @@
     7.4  #define NETCODE_ACCEPT 0x02
     7.5  #define NETCODE_DECLINE 0x04
     7.6  #define NETCODE_GAMEINFO 0x10
     7.7 +#define NETCODE_PGNDATA 0x11
     7.8  #define NETCODE_MOVE 0x20
     7.9  #define NETCODE_CHECK 0x22
    7.10  #define NETCODE_CHECKMATE 0x24
    7.11 @@ -49,7 +50,7 @@
    7.12  #define NETCODE_TIMEOVER 0x44
    7.13  #define NETCODE_CONNLOST 0x80
    7.14  
    7.15 -#define NETCODE_VERSION 15
    7.16 +#define NETCODE_VERSION 16
    7.17  
    7.18  typedef struct {
    7.19      int fd; /* -1, if we are the client */
     8.1 --- a/src/server.c	Mon Jun 16 13:45:31 2014 +0200
     8.2 +++ b/src/server.c	Mon Jun 16 15:41:06 2014 +0200
     8.3 @@ -30,6 +30,8 @@
     8.4  #include "terminal-chess.h"
     8.5  #include "game.h"
     8.6  #include <ncurses.h>
     8.7 +#include <errno.h>
     8.8 +#include <string.h>
     8.9  
    8.10  static int server_open(Server *server, char *port) {
    8.11      printw("\nListening for client...\n");
    8.12 @@ -64,6 +66,31 @@
    8.13      Server server;
    8.14      
    8.15      dump_gameinfo(&(settings->gameinfo));
    8.16 +    GameState continuegame;
    8.17 +    gamestate_init(&continuegame);
    8.18 +    if (settings->continuepgn) {
    8.19 +        // preload PGN data before handshake
    8.20 +        FILE *pgnfile = fopen(settings->continuepgn, "r");
    8.21 +        if (pgnfile) {
    8.22 +            int result = read_pgn(pgnfile, &continuegame,
    8.23 +                &(settings->gameinfo));
    8.24 +            fclose(pgnfile);
    8.25 +            if (result != EXIT_SUCCESS) {
    8.26 +                addstr("Invalid PGN file content.\n");
    8.27 +                return EXIT_FAILURE;
    8.28 +            }
    8.29 +            if (!is_game_running(&continuegame)) {
    8.30 +                addstr("Game has ended. Use -S to analyze it.\n");
    8.31 +                return EXIT_FAILURE;
    8.32 +            }
    8.33 +            addch('\n');
    8.34 +            dump_moveinfo(&continuegame);
    8.35 +            addch('\n');
    8.36 +        } else {
    8.37 +            printw("Can't read PGN file (%s)\n", strerror(errno));
    8.38 +            return EXIT_FAILURE;
    8.39 +        }
    8.40 +    }
    8.41      
    8.42      if (server_open(&server, settings->port)) {
    8.43          net_destroy(&server);
    8.44 @@ -76,16 +103,49 @@
    8.45      }
    8.46  
    8.47      int fd = server.client->fd;
    8.48 -    net_send_data(fd, NETCODE_GAMEINFO,
    8.49 -        &(settings->gameinfo), sizeof(GameInfo));
    8.50 +    if (settings->continuepgn) {
    8.51 +        // Continue game, send PGN data
    8.52 +        uint16_t mc = 0;
    8.53 +        MoveList *movelist = continuegame.movelist;
    8.54 +        while (movelist) {
    8.55 +            mc++;
    8.56 +            movelist = movelist->next;
    8.57 +        }
    8.58 +        
    8.59 +        Move* moves = calloc(mc, sizeof(Move));
    8.60 +        
    8.61 +        movelist = continuegame.movelist;
    8.62 +        mc = 0;
    8.63 +        while (movelist) {
    8.64 +            moves[mc] = movelist->move;
    8.65 +            mc++;
    8.66 +            movelist = movelist->next;
    8.67 +        }
    8.68 +        
    8.69 +        size_t pgndata_size = sizeof(GameInfo)+sizeof(mc)+mc*sizeof(Move);
    8.70 +        char *pgndata = malloc(pgndata_size);
    8.71 +        memcpy(pgndata, &(settings->gameinfo), sizeof(GameInfo));
    8.72 +        memcpy(pgndata+sizeof(GameInfo), &mc, sizeof(mc));
    8.73 +        memcpy(pgndata+sizeof(GameInfo)+sizeof(mc), moves, mc*sizeof(Move));
    8.74 +        free(moves);
    8.75 +        net_send_data(fd, NETCODE_PGNDATA, pgndata, pgndata_size);
    8.76 +        free(pgndata);
    8.77 +    } else {
    8.78 +        // Start new game
    8.79 +        net_send_data(fd, NETCODE_GAMEINFO,
    8.80 +            &(settings->gameinfo), sizeof(GameInfo));
    8.81 +    }
    8.82      addstr("\rClient connected - awaiting challenge acceptance...");
    8.83      refresh();
    8.84      int code = net_recieve_code(fd);
    8.85      if (code == NETCODE_ACCEPT) {
    8.86          addstr("\rClient connected - challenge accepted.");
    8.87          clrtoeol();
    8.88 -        
    8.89 -        game_start(settings, fd);
    8.90 +        if (settings->continuepgn) {
    8.91 +            game_continue(settings, fd, &continuegame);
    8.92 +        } else {
    8.93 +            game_start(settings, fd);
    8.94 +        }
    8.95      } else if (code == NETCODE_DECLINE) {
    8.96          addstr("\rClient connected - challenge declined.");
    8.97          clrtoeol();
     9.1 --- a/src/terminal-chess.h	Mon Jun 16 13:45:31 2014 +0200
     9.2 +++ b/src/terminal-chess.h	Mon Jun 16 15:41:06 2014 +0200
     9.3 @@ -53,6 +53,7 @@
     9.4  #define is_server(settings) !((settings)->serverhost)
     9.5  
     9.6  void dump_gameinfo(GameInfo *gameinfo);
     9.7 +void dump_moveinfo(GameState *gamestate);
     9.8  
     9.9  int server_run(Settings* settings);
    9.10  int client_run(Settings* settings);

mercurial