Wed, 09 Apr 2014 11:12:04 +0200
implemented time control
conf.mk | file | annotate | diff | comparison | revisions | |
src/chess/rules.c | file | annotate | diff | comparison | revisions | |
src/chess/rules.h | file | annotate | diff | comparison | revisions | |
src/game.c | file | annotate | diff | comparison | revisions | |
src/main.c | file | annotate | diff | comparison | revisions | |
src/network.h | file | annotate | diff | comparison | revisions |
1.1 --- a/conf.mk Wed Apr 09 09:34:07 2014 +0200 1.2 +++ b/conf.mk Wed Apr 09 11:12:04 2014 +0200 1.3 @@ -35,7 +35,7 @@ 1.4 CFLAGS = -O2 -std=gnu99 1.5 CFLAGS_D = -g -std=gnu99 -Wall -pedantic 1.6 LD = gcc 1.7 -LDFLAGS = -lncurses 1.8 +LDFLAGS = -lncurses -lrt 1.9 ARFLAGS = -r 1.10 MKDIRFLAGS = -p 1.11 RMFLAGS = -f -R
2.1 --- a/src/chess/rules.c Wed Apr 09 09:34:07 2014 +0200 2.2 +++ b/src/chess/rules.c Wed Apr 09 11:12:04 2014 +0200 2.3 @@ -47,10 +47,27 @@ 2.4 elem->next = NULL; 2.5 elem->move = *move; 2.6 2.7 + clock_gettime(CLOCK_REALTIME, &(elem->move.timestamp)); 2.8 + 2.9 if (gamestate->lastmove) { 2.10 + struct timespec *lasttstamp = &(gamestate->lastmove->move.timestamp); 2.11 + time_t sec = elem->move.timestamp.tv_sec - lasttstamp->tv_sec; 2.12 + long int nanos; 2.13 + if (elem->move.timestamp.tv_nsec < lasttstamp->tv_nsec) { 2.14 + nanos = 1e9L-(lasttstamp->tv_nsec - elem->move.timestamp.tv_nsec); 2.15 + sec--; 2.16 + } else { 2.17 + nanos = elem->move.timestamp.tv_nsec - lasttstamp->tv_nsec; 2.18 + } 2.19 + 2.20 + elem->move.movetime.tv_sec = sec; 2.21 + elem->move.movetime.tv_nsec = nanos; 2.22 + 2.23 gamestate->lastmove->next = elem; 2.24 gamestate->lastmove = elem; 2.25 } else { 2.26 + elem->move.movetime.tv_nsec = 0; 2.27 + elem->move.movetime.tv_sec = 0; 2.28 gamestate->movelist = gamestate->lastmove = elem; 2.29 } 2.30 } 2.31 @@ -524,3 +541,59 @@ 2.32 return 0; 2.33 } 2.34 } 2.35 + 2.36 +uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, 2.37 + uint8_t color) { 2.38 + if (!gameinfo->timecontrol) { 2.39 + return 0; 2.40 + } 2.41 + 2.42 + if (gamestate->movelist) { 2.43 + uint16_t time = gameinfo->time; 2.44 + long int nanos = 0; 2.45 + 2.46 + MoveList *movelist = color == WHITE ? 2.47 + gamestate->movelist : gamestate->movelist->next; 2.48 + 2.49 + while (movelist) { 2.50 + time += gameinfo->addtime; 2.51 + 2.52 + struct timespec *movetime = &(movelist->move.movetime); 2.53 + if (movetime->tv_sec >= time) { 2.54 + return 0; 2.55 + } 2.56 + 2.57 + time -= movetime->tv_sec; 2.58 + nanos += movetime->tv_nsec; 2.59 + 2.60 + movelist = movelist->next ? movelist->next->next : NULL; 2.61 + } 2.62 + 2.63 + time_t sec; 2.64 + movelist = gamestate->lastmove; 2.65 + if ((movelist->move.piece & COLOR_MASK) != color) { 2.66 + struct timespec *lastmovetstamp = &(movelist->move.timestamp); 2.67 + struct timespec currenttstamp; 2.68 + clock_gettime(CLOCK_REALTIME, ¤ttstamp); 2.69 + nanos += currenttstamp.tv_nsec - lastmovetstamp->tv_nsec; 2.70 + sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec; 2.71 + if (sec >= time) { 2.72 + return 0; 2.73 + } 2.74 + 2.75 + time -= sec; 2.76 + } 2.77 + 2.78 + sec = nanos / 1e9L; 2.79 + 2.80 + if (sec >= time) { 2.81 + return 0; 2.82 + } 2.83 + 2.84 + time -= sec; 2.85 + 2.86 + return time; 2.87 + } else { 2.88 + return gameinfo->time; 2.89 + } 2.90 +}
3.1 --- a/src/chess/rules.h Wed Apr 09 09:34:07 2014 +0200 3.2 +++ b/src/chess/rules.h Wed Apr 09 11:12:04 2014 +0200 3.3 @@ -264,5 +264,18 @@ 3.4 */ 3.5 void apply_move(GameState *gamestate, Move *move); 3.6 3.7 + 3.8 +/** 3.9 + * Returns the remaining time on the clock for the specified player. 3.10 + * 3.11 + * @param gameinfo the information about the game 3.12 + * @param gamestate the current game state 3.13 + * @param color either BLACK or WHITE 3.14 + * @return the remaining time - if time control is disabled, this function 3.15 + * always returns zero 3.16 + */ 3.17 +uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, 3.18 + uint8_t color); 3.19 + 3.20 #endif /* RULES_H */ 3.21
4.1 --- a/src/game.c Wed Apr 09 09:34:07 2014 +0200 4.2 +++ b/src/game.c Wed Apr 09 11:12:04 2014 +0200 4.3 @@ -35,21 +35,36 @@ 4.4 #include <inttypes.h> 4.5 4.6 static const uint8_t boardx = 10, boardy = 10; 4.7 +static int inputy = 21; /* should be overridden on game startup */ 4.8 4.9 -static void draw_time(GameState *gamestate, GameInfo *gameinfo) { 4.10 +static int timecontrol(GameState *gamestate, GameInfo *gameinfo) { 4.11 if (gameinfo->timecontrol) { 4.12 - // TODO: correct time display 4.13 - 4.14 - uint16_t whitem = gameinfo->time / 60; 4.15 - uint16_t whites = gameinfo->time % 60; 4.16 - uint16_t blackm = gameinfo->time / 60; 4.17 - uint16_t blacks = gameinfo->time % 60; 4.18 - 4.19 + uint16_t white = remaining_movetime(gameinfo, gamestate, WHITE); 4.20 + uint16_t black = remaining_movetime(gameinfo, gamestate, BLACK); 4.21 mvprintw(boardy+4, boardx-1, 4.22 - "White time: %4" PRIu16 ":%02" PRIu16, whitem, whites); 4.23 + "White time: %4" PRIu16 ":%02" PRIu16, 4.24 + white / 60, white % 60); 4.25 mvprintw(boardy+5, boardx-1, 4.26 - "Black time: %4" PRIu16 ":%02" PRIu16, blackm, blacks); 4.27 + "Black time: %4" PRIu16 ":%02" PRIu16, 4.28 + black / 60, black % 60); 4.29 + 4.30 + if (white == 0) { 4.31 + move(inputy, 0); 4.32 + printw("Time is over - Black wins!"); 4.33 + clrtobot(); 4.34 + refresh(); 4.35 + return 1; 4.36 + } 4.37 + if (black == 0) { 4.38 + move(inputy, 0); 4.39 + printw("Time is over - White wins!"); 4.40 + clrtobot(); 4.41 + refresh(); 4.42 + return 1; 4.43 + } 4.44 } 4.45 + 4.46 + return 0; 4.47 } 4.48 4.49 static void draw_board(GameState *gamestate) { 4.50 @@ -156,16 +171,18 @@ 4.51 size_t bufpos = 0; 4.52 char movestr[buflen]; 4.53 4.54 - int inputy = getmaxy(stdscr) - 6; 4.55 + flushinp(); 4.56 while (1) { 4.57 - draw_time(gamestate, gameinfo); 4.58 + if (timecontrol(gamestate, gameinfo)) { 4.59 + return 1; 4.60 + } 4.61 + 4.62 move(inputy, 0); 4.63 printw( 4.64 "Use chess notation to enter your move.\n" 4.65 "Or type 'surr' to surrender or 'remis' to end with remis.\n\n" 4.66 "Type your move: "); 4.67 clrtoeol(); 4.68 - refresh(); 4.69 4.70 if (asyncgetnstr(movestr, &bufpos, buflen)) { 4.71 if (strncmp(movestr, "surr", buflen) == 0) { 4.72 @@ -210,15 +227,21 @@ 4.73 } 4.74 } 4.75 4.76 -static int sendmove(GameState *gamestate, int opponent) { 4.77 +static int sendmove(GameState *gamestate, GameInfo *gameinfo, int opponent) { 4.78 4.79 const size_t buflen = 8; 4.80 + size_t bufpos = 0; 4.81 char movestr[buflen]; 4.82 _Bool remisrejected = FALSE; 4.83 uint8_t code; 4.84 4.85 - int inputy = getmaxy(stdscr) - 6; 4.86 + flushinp(); 4.87 while (1) { 4.88 + if (timecontrol(gamestate, gameinfo)) { 4.89 + net_send_code(opponent, NETCODE_TIMEOVER); 4.90 + return 1; 4.91 + } 4.92 + 4.93 move(inputy, 0); 4.94 if (remisrejected) { 4.95 printw( 4.96 @@ -232,68 +255,69 @@ 4.97 "Type your move: "); 4.98 } 4.99 clrtoeol(); 4.100 - refresh(); 4.101 - getnstr(movestr, buflen); 4.102 - 4.103 - if (strncmp(movestr, "surr", buflen) == 0) { 4.104 - printw("You surrendered!"); 4.105 - clrtoeol(); 4.106 - refresh(); 4.107 - net_send_code(opponent, NETCODE_SURRENDER); 4.108 - return 1; 4.109 - } else if (strncmp(movestr, "remis", buflen) == 0) { 4.110 - if (!remisrejected) { 4.111 - net_send_code(opponent, NETCODE_REMIS); 4.112 - printw("Remis offer sent - waiting for acceptance..."); 4.113 + 4.114 + if (asyncgetnstr(movestr, &bufpos, buflen)) { 4.115 + if (strncmp(movestr, "surr", buflen) == 0) { 4.116 + printw("You surrendered!"); 4.117 + clrtoeol(); 4.118 refresh(); 4.119 - if (net_recieve_code(opponent) == NETCODE_ACCEPT) { 4.120 - printw("\rRemis accepted!"); 4.121 - clrtoeol(); 4.122 + net_send_code(opponent, NETCODE_SURRENDER); 4.123 + return 1; 4.124 + } else if (strncmp(movestr, "remis", buflen) == 0) { 4.125 + if (!remisrejected) { 4.126 + net_send_code(opponent, NETCODE_REMIS); 4.127 + printw("Remis offer sent - waiting for acceptance..."); 4.128 refresh(); 4.129 - return 1; 4.130 - } else { 4.131 - remisrejected = TRUE; 4.132 - } 4.133 - } 4.134 - } else { 4.135 - Move move; 4.136 - int eval_result = eval_move(gamestate, movestr, &move); 4.137 - switch (eval_result) { 4.138 - case VALID_MOVE_SYNTAX: 4.139 - net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); 4.140 - code = net_recieve_code(opponent); 4.141 - move.check = code == NETCODE_CHECK; 4.142 - gamestate->checkmate = code == NETCODE_CHECKMATE; 4.143 - gamestate->stalemate = code == NETCODE_STALEMATE; 4.144 - if (code == NETCODE_DECLINE) { 4.145 - printw("Invalid move."); 4.146 - } else { 4.147 - apply_move(gamestate, &move); 4.148 - if (gamestate->checkmate) { 4.149 - printw("Checkmate!"); 4.150 + if (net_recieve_code(opponent) == NETCODE_ACCEPT) { 4.151 + printw("\rRemis accepted!"); 4.152 clrtoeol(); 4.153 - return 1; 4.154 - } else if (gamestate->stalemate) { 4.155 - printw("Stalemate!"); 4.156 - clrtoeol(); 4.157 + refresh(); 4.158 return 1; 4.159 } else { 4.160 - return 0; 4.161 + remisrejected = TRUE; 4.162 } 4.163 } 4.164 - break; 4.165 - default: 4.166 - eval_move_failed_msg(eval_result); 4.167 + } else { 4.168 + Move move; 4.169 + int eval_result = eval_move(gamestate, movestr, &move); 4.170 + switch (eval_result) { 4.171 + case VALID_MOVE_SYNTAX: 4.172 + net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); 4.173 + code = net_recieve_code(opponent); 4.174 + move.check = code == NETCODE_CHECK; 4.175 + gamestate->checkmate = code == NETCODE_CHECKMATE; 4.176 + gamestate->stalemate = code == NETCODE_STALEMATE; 4.177 + if (code == NETCODE_DECLINE) { 4.178 + printw("Invalid move."); 4.179 + } else { 4.180 + apply_move(gamestate, &move); 4.181 + if (gamestate->checkmate) { 4.182 + printw("Checkmate!"); 4.183 + clrtoeol(); 4.184 + return 1; 4.185 + } else if (gamestate->stalemate) { 4.186 + printw("Stalemate!"); 4.187 + clrtoeol(); 4.188 + return 1; 4.189 + } else { 4.190 + return 0; 4.191 + } 4.192 + } 4.193 + break; 4.194 + default: 4.195 + eval_move_failed_msg(eval_result); 4.196 + } 4.197 + clrtoeol(); 4.198 } 4.199 - clrtoeol(); 4.200 } 4.201 } 4.202 } 4.203 4.204 -static int recvmove(GameState *gamestate, int opponent) { 4.205 +static int recvmove(GameState *gamestate, GameInfo *gameinfo, int opponent) { 4.206 4.207 - int inputy = getmaxy(stdscr) - 6; 4.208 while (1) { 4.209 + timecontrol(gamestate, gameinfo); 4.210 + 4.211 move(inputy, 0); 4.212 printw("Awaiting opponent move..."); 4.213 clrtoeol(); 4.214 @@ -304,44 +328,48 @@ 4.215 4.216 Move move; 4.217 switch (code) { 4.218 - case NETCODE_SURRENDER: 4.219 - printw("\rYour opponent surrendered!"); 4.220 + case NETCODE_TIMEOVER: 4.221 + printw("\rYour opponent's time ran out - you win!"); 4.222 + clrtoeol(); 4.223 + return 1; 4.224 + case NETCODE_SURRENDER: 4.225 + printw("\rYour opponent surrendered!"); 4.226 + clrtoeol(); 4.227 + return 1; 4.228 + case NETCODE_REMIS: 4.229 + if (prompt_yesno( 4.230 + "\rYour opponent offers remis - do you accept")) { 4.231 + printw("\rRemis accepted!"); 4.232 clrtoeol(); 4.233 + net_send_code(opponent, NETCODE_ACCEPT); 4.234 return 1; 4.235 - case NETCODE_REMIS: 4.236 - if (prompt_yesno( 4.237 - "\rYour opponent offers remis - do you accept")) { 4.238 - printw("\rRemis accepted!"); 4.239 + } else { 4.240 + net_send_code(opponent, NETCODE_DECLINE); 4.241 + } 4.242 + break; 4.243 + case NETCODE_MOVE: 4.244 + net_recieve_data(opponent, &move, sizeof(Move)); 4.245 + if (validate_move(gamestate, &move)) { 4.246 + apply_move(gamestate, &move); 4.247 + if (move.check) { 4.248 + net_send_code(opponent, NETCODE_CHECK); 4.249 + } else if (gamestate->checkmate) { 4.250 + net_send_code(opponent, NETCODE_CHECKMATE); 4.251 + printw("\rCheckmate!"); 4.252 clrtoeol(); 4.253 - net_send_code(opponent, NETCODE_ACCEPT); 4.254 + return 1; 4.255 + } else if (gamestate->stalemate) { 4.256 + net_send_code(opponent, NETCODE_STALEMATE); 4.257 + printw("\rStalemate!"); 4.258 + clrtoeol(); 4.259 return 1; 4.260 } else { 4.261 - net_send_code(opponent, NETCODE_DECLINE); 4.262 + net_send_code(opponent, NETCODE_ACCEPT); 4.263 } 4.264 - break; 4.265 - case NETCODE_MOVE: 4.266 - net_recieve_data(opponent, &move, sizeof(Move)); 4.267 - if (validate_move(gamestate, &move)) { 4.268 - apply_move(gamestate, &move); 4.269 - if (move.check) { 4.270 - net_send_code(opponent, NETCODE_CHECK); 4.271 - } else if (gamestate->checkmate) { 4.272 - net_send_code(opponent, NETCODE_CHECKMATE); 4.273 - printw("\rCheckmate!"); 4.274 - clrtoeol(); 4.275 - return 1; 4.276 - } else if (gamestate->stalemate) { 4.277 - net_send_code(opponent, NETCODE_STALEMATE); 4.278 - printw("\rStalemate!"); 4.279 - clrtoeol(); 4.280 - return 1; 4.281 - } else { 4.282 - net_send_code(opponent, NETCODE_ACCEPT); 4.283 - } 4.284 - return 0; 4.285 - } else { 4.286 - net_send_code(opponent, NETCODE_DECLINE); 4.287 - } 4.288 + return 0; 4.289 + } else { 4.290 + net_send_code(opponent, NETCODE_DECLINE); 4.291 + } 4.292 } 4.293 } 4.294 } 4.295 @@ -361,6 +389,8 @@ 4.296 } 4.297 4.298 void game_start_singlemachine(Settings *settings) { 4.299 + inputy = getmaxy(stdscr) - 6; 4.300 + 4.301 GameState gamestate; 4.302 memset(&gamestate, 0, sizeof(GameState)); 4.303 init_board(&gamestate); 4.304 @@ -385,10 +415,11 @@ 4.305 } 4.306 4.307 void game_start(Settings *settings, int opponent) { 4.308 + inputy = getmaxy(stdscr) - 6; 4.309 + 4.310 _Bool myturn = is_server(settings) == 4.311 (settings->gameinfo.servercolor == WHITE); 4.312 4.313 - // TODO: time limit 4.314 GameState gamestate; 4.315 memset(&gamestate, 0, sizeof(GameState)); 4.316 init_board(&gamestate); 4.317 @@ -399,10 +430,9 @@ 4.318 clear(); 4.319 draw_board(&gamestate); 4.320 if (myturn) { 4.321 - running = !sendmove(&gamestate, opponent); 4.322 + running = !sendmove(&gamestate, &(settings->gameinfo), opponent); 4.323 } else { 4.324 - running = !recvmove(&gamestate, opponent); 4.325 - flushinp(); // flush any input the user hacked in while waiting 4.326 + running = !recvmove(&gamestate, &(settings->gameinfo), opponent); 4.327 } 4.328 myturn ^= TRUE; 4.329 } while (running); 4.330 @@ -415,5 +445,7 @@ 4.331 mvaddstr(getmaxy(stdscr)-1, 0, 4.332 "Game has ended. Press any key to leave..."); 4.333 refresh(); 4.334 + cbreak(); 4.335 + flushinp(); 4.336 getch(); 4.337 }
5.1 --- a/src/main.c Wed Apr 09 09:34:07 2014 +0200 5.2 +++ b/src/main.c Wed Apr 09 11:12:04 2014 +0200 5.3 @@ -116,7 +116,7 @@ 5.4 printw("Game details\n"); 5.5 attroff(A_UNDERLINE); 5.6 printw(" Server: %s\n Client: %s\n", 5.7 - serverwhite?"white":"black", serverwhite?"black":"White" 5.8 + serverwhite?"White":"Black", serverwhite?"Black":"White" 5.9 ); 5.10 if (gameinfo->timecontrol) { 5.11 if (gameinfo->time % 60) {
6.1 --- a/src/network.h Wed Apr 09 09:34:07 2014 +0200 6.2 +++ b/src/network.h Wed Apr 09 11:12:04 2014 +0200 6.3 @@ -46,8 +46,9 @@ 6.4 #define NETCODE_CHECK 0x23 6.5 #define NETCODE_CHECKMATE 0x24 6.6 #define NETCODE_STALEMATE 0x25 6.7 +#define NETCODE_TIMEOVER 0x26 6.8 6.9 -#define NETCODE_VERSION 10 6.10 +#define NETCODE_VERSION 11 6.11 6.12 typedef struct { 6.13 int fd; /* -1, if we are the client */