Mon, 16 Jun 2014 15:41:06 +0200
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 |
--- a/src/chess/pgn.h Mon Jun 16 13:45:31 2014 +0200 +++ b/src/chess/pgn.h Mon Jun 16 15:41:06 2014 +0200 @@ -41,7 +41,6 @@ int read_pgn(FILE *stream, GameState *gamestate, GameInfo *gameinfo); size_t write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo); - #ifdef __cplusplus } #endif
--- a/src/chess/rules.c Mon Jun 16 13:45:31 2014 +0200 +++ b/src/chess/rules.c Mon Jun 16 15:41:06 2014 +0200 @@ -40,7 +40,7 @@ *lastmovecopy = *(simulation.lastmove); simulation.movelist = simulation.lastmove = lastmovecopy; } - + return simulation; } @@ -421,13 +421,13 @@ } } else { /* bishop aspect */ - int dr = move->torow > move->fromrow ? 1 : -1; - int df = move->tofile > move->fromfile ? 1 : -1; + int dr = threat->torow > threat->fromrow ? 1 : -1; + int df = threat->tofile > threat->fromfile ? 1 : -1; - uint8_t row = move->fromrow; - uint8_t file = move->fromfile; - while (!canescape && file != move->tofile - df - && row != move->torow - dr) { + uint8_t row = threat->fromrow; + uint8_t file = threat->fromfile; + while (!canescape && file != threat->tofile - df + && row != threat->torow - dr) { row += dr; file += df; canescape |= is_protected(&simulation, row, file,
--- a/src/client.c Mon Jun 16 13:45:31 2014 +0200 +++ b/src/client.c Mon Jun 16 15:41:06 2014 +0200 @@ -73,9 +73,10 @@ return EXIT_FAILURE; } - if (net_recieve_code(server.fd) == NETCODE_GAMEINFO) { - net_recieve_data(server.fd, &(settings->gameinfo), - sizeof(settings->gameinfo)); + uint8_t code = net_recieve_code(server.fd); + if (code == NETCODE_GAMEINFO) { + // Start new game + net_recieve_data(server.fd, &(settings->gameinfo), sizeof(GameInfo)); dump_gameinfo(&(settings->gameinfo)); if (prompt_yesno("Accept challenge")) { net_send_code(server.fd, NETCODE_ACCEPT); @@ -83,6 +84,28 @@ } else { net_send_code(server.fd, NETCODE_DECLINE); } + } else if (code == NETCODE_PGNDATA) { + net_recieve_data(server.fd, &(settings->gameinfo), sizeof(GameInfo)); + dump_gameinfo(&(settings->gameinfo)); + uint16_t mc; + net_recieve_data(server.fd, &mc, sizeof(mc)); + Move *moves = calloc(mc, sizeof(Move)); + net_recieve_data(server.fd, moves, mc*sizeof(Move)); + GameState continuegame; + gamestate_init(&continuegame); + for (size_t i = 0 ; i < mc ; i++) { + apply_move(&continuegame, &(moves[i])); + } + free(moves); + addch('\n'); + dump_moveinfo(&continuegame); + if (prompt_yesno( + "\n\nServer wants to continue a game. Accept challenge")) { + net_send_code(server.fd, NETCODE_ACCEPT); + game_continue(settings, server.fd, &continuegame); + } else { + net_send_code(server.fd, NETCODE_DECLINE); + } } else { addstr("Server sent invalid gameinfo."); net_destroy(&server);
--- a/src/game.c Mon Jun 16 13:45:31 2014 +0200 +++ b/src/game.c Mon Jun 16 15:41:06 2014 +0200 @@ -174,7 +174,7 @@ char filename[64]; int y = getcury(stdscr); - if (getnstr(filename, 64) == OK) { + if (getnstr(filename, 64) == OK && filename[0] != '\0') { move(y, 0); FILE *file = fopen(filename, "w"); if (file) { @@ -322,8 +322,7 @@ int eval_result = eval_move(gamestate, movestr, &move, mycolor); switch (eval_result) { case VALID_MOVE_SYNTAX: - net_send_data(opponent, NETCODE_MOVE, &move, - sizeof(Move)-8); + net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); code = net_recieve_code(opponent); move.check = code == NETCODE_CHECK || code == NETCODE_CHECKMATE; @@ -423,13 +422,11 @@ } break; case NETCODE_MOVE: - net_recieve_data(opponent, &move, sizeof(Move)-8); + net_recieve_data(opponent, &move, sizeof(Move)); code = validate_move(gamestate, &move); if (code == VALID_MOVE_SEMANTICS) { apply_move(gamestate, &move); - if (move.check) { - net_send_code(opponent, NETCODE_CHECK); - } else if (gamestate->checkmate) { + if (gamestate->checkmate) { net_send_code(opponent, NETCODE_CHECKMATE); printw("\rCheckmate!"); clrtoeol(); @@ -439,6 +436,8 @@ printw("\rStalemate!"); clrtoeol(); return 1; + } else if (move.check) { + net_send_code(opponent, NETCODE_CHECK); } else { net_send_code(opponent, NETCODE_ACCEPT); } @@ -523,28 +522,34 @@ post_game(&gamestate, &(settings->gameinfo)); } -void game_start(Settings *settings, int opponent) { +void game_continue(Settings *settings, int opponent, GameState *gamestate) { inputy = getmaxy(stdscr) - 6; - _Bool myturn = is_server(settings) == - (settings->gameinfo.servercolor == WHITE); - uint8_t mycolor = myturn ? WHITE : BLACK; + uint8_t mycolor = is_server(settings) ? settings->gameinfo.servercolor : + opponent_color(settings->gameinfo.servercolor); - GameState gamestate; - gamestate_init(&gamestate); + _Bool myturn = (gamestate->lastmove ? + (gamestate->lastmove->move.piece & COLOR_MASK) : WHITE) != mycolor; _Bool running; do { clear(); - draw_board(&gamestate, mycolor); + draw_board(gamestate, mycolor); if (myturn) { - running = !sendmove(&gamestate, &(settings->gameinfo), + running = !sendmove(gamestate, &(settings->gameinfo), opponent, mycolor); } else { - running = !recvmove(&gamestate, &(settings->gameinfo), opponent); + running = !recvmove(gamestate, &(settings->gameinfo), opponent); } myturn ^= TRUE; } while (running); - post_game(&gamestate, &(settings->gameinfo)); + post_game(gamestate, &(settings->gameinfo)); } + +void game_start(Settings *settings, int opponent) { + GameState gamestate; + gamestate_init(&gamestate); + + game_continue(settings, opponent, &gamestate); +}
--- a/src/game.h Mon Jun 16 13:45:31 2014 +0200 +++ b/src/game.h Mon Jun 16 15:41:06 2014 +0200 @@ -38,6 +38,7 @@ #endif void game_start(Settings *settings, int opponent); +void game_continue(Settings *settings, int opponent, GameState *gamestate); void game_start_singlemachine(Settings *settings); #ifdef __cplusplus
--- a/src/main.c Mon Jun 16 13:45:31 2014 +0200 +++ b/src/main.c Mon Jun 16 15:41:06 2014 +0200 @@ -116,12 +116,6 @@ fprintf(stderr, "The options -c and -S are mutually exclusive\n"); return 1; } - // TODO: implement - if (!settings->singlemachine) { - fprintf(stderr, "Game continuation currently not supported for " - "network games.\n"); - return 1; - } } return 0; @@ -157,6 +151,24 @@ refresh(); } +void dump_moveinfo(GameState *gamestate) { + int i = 1; + for (MoveList *movelist = gamestate->movelist ; + movelist ; movelist = movelist->next) { + if (++i % 2 == 0) { + printw("%d. %s", i/2, movelist->move.string); + } else { + printw(" %s", movelist->move.string); + } + if (i % 20) { + addch(' '); + } else { + addch('\n'); + } + } + refresh(); +} + void leavescr() { endwin(); }
--- a/src/network.h Mon Jun 16 13:45:31 2014 +0200 +++ b/src/network.h Mon Jun 16 15:41:06 2014 +0200 @@ -40,6 +40,7 @@ #define NETCODE_ACCEPT 0x02 #define NETCODE_DECLINE 0x04 #define NETCODE_GAMEINFO 0x10 +#define NETCODE_PGNDATA 0x11 #define NETCODE_MOVE 0x20 #define NETCODE_CHECK 0x22 #define NETCODE_CHECKMATE 0x24 @@ -49,7 +50,7 @@ #define NETCODE_TIMEOVER 0x44 #define NETCODE_CONNLOST 0x80 -#define NETCODE_VERSION 15 +#define NETCODE_VERSION 16 typedef struct { int fd; /* -1, if we are the client */
--- a/src/server.c Mon Jun 16 13:45:31 2014 +0200 +++ b/src/server.c Mon Jun 16 15:41:06 2014 +0200 @@ -30,6 +30,8 @@ #include "terminal-chess.h" #include "game.h" #include <ncurses.h> +#include <errno.h> +#include <string.h> static int server_open(Server *server, char *port) { printw("\nListening for client...\n"); @@ -64,6 +66,31 @@ Server server; dump_gameinfo(&(settings->gameinfo)); + GameState continuegame; + gamestate_init(&continuegame); + if (settings->continuepgn) { + // preload PGN data before handshake + FILE *pgnfile = fopen(settings->continuepgn, "r"); + if (pgnfile) { + int result = read_pgn(pgnfile, &continuegame, + &(settings->gameinfo)); + fclose(pgnfile); + if (result != EXIT_SUCCESS) { + addstr("Invalid PGN file content.\n"); + return EXIT_FAILURE; + } + if (!is_game_running(&continuegame)) { + addstr("Game has ended. Use -S to analyze it.\n"); + return EXIT_FAILURE; + } + addch('\n'); + dump_moveinfo(&continuegame); + addch('\n'); + } else { + printw("Can't read PGN file (%s)\n", strerror(errno)); + return EXIT_FAILURE; + } + } if (server_open(&server, settings->port)) { net_destroy(&server); @@ -76,16 +103,49 @@ } int fd = server.client->fd; - net_send_data(fd, NETCODE_GAMEINFO, - &(settings->gameinfo), sizeof(GameInfo)); + if (settings->continuepgn) { + // Continue game, send PGN data + uint16_t mc = 0; + MoveList *movelist = continuegame.movelist; + while (movelist) { + mc++; + movelist = movelist->next; + } + + Move* moves = calloc(mc, sizeof(Move)); + + movelist = continuegame.movelist; + mc = 0; + while (movelist) { + moves[mc] = movelist->move; + mc++; + movelist = movelist->next; + } + + size_t pgndata_size = sizeof(GameInfo)+sizeof(mc)+mc*sizeof(Move); + char *pgndata = malloc(pgndata_size); + memcpy(pgndata, &(settings->gameinfo), sizeof(GameInfo)); + memcpy(pgndata+sizeof(GameInfo), &mc, sizeof(mc)); + memcpy(pgndata+sizeof(GameInfo)+sizeof(mc), moves, mc*sizeof(Move)); + free(moves); + net_send_data(fd, NETCODE_PGNDATA, pgndata, pgndata_size); + free(pgndata); + } else { + // Start new game + net_send_data(fd, NETCODE_GAMEINFO, + &(settings->gameinfo), sizeof(GameInfo)); + } addstr("\rClient connected - awaiting challenge acceptance..."); refresh(); int code = net_recieve_code(fd); if (code == NETCODE_ACCEPT) { addstr("\rClient connected - challenge accepted."); clrtoeol(); - - game_start(settings, fd); + if (settings->continuepgn) { + game_continue(settings, fd, &continuegame); + } else { + game_start(settings, fd); + } } else if (code == NETCODE_DECLINE) { addstr("\rClient connected - challenge declined."); clrtoeol();
--- a/src/terminal-chess.h Mon Jun 16 13:45:31 2014 +0200 +++ b/src/terminal-chess.h Mon Jun 16 15:41:06 2014 +0200 @@ -53,6 +53,7 @@ #define is_server(settings) !((settings)->serverhost) void dump_gameinfo(GameInfo *gameinfo); +void dump_moveinfo(GameState *gamestate); int server_run(Settings* settings); int client_run(Settings* settings);