Mon, 07 Apr 2014 17:39:46 +0200
experimental async input for single machine mode
src/chess/rules.h | file | annotate | diff | comparison | revisions | |
src/game.c | file | annotate | diff | comparison | revisions | |
src/input.c | file | annotate | diff | comparison | revisions | |
src/input.h | file | annotate | diff | comparison | revisions | |
src/main.c | 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/rules.h Mon Apr 07 14:08:57 2014 +0200 1.2 +++ b/src/chess/rules.h Mon Apr 07 17:39:46 2014 +0200 1.3 @@ -87,6 +87,14 @@ 1.4 MoveList* next; 1.5 }; 1.6 1.7 + 1.8 +typedef struct { 1.9 + uint8_t servercolor; 1.10 + _Bool timecontrol; 1.11 + uint16_t time; 1.12 + uint16_t addtime; 1.13 +} GameInfo; 1.14 + 1.15 typedef struct { 1.16 Board board; 1.17 uint8_t mycolor;
2.1 --- a/src/game.c Mon Apr 07 14:08:57 2014 +0200 2.2 +++ b/src/game.c Mon Apr 07 17:39:46 2014 +0200 2.3 @@ -32,11 +32,27 @@ 2.4 #include "input.h" 2.5 #include <ncurses.h> 2.6 #include <string.h> 2.7 +#include <inttypes.h> 2.8 2.9 static const uint8_t boardx = 10, boardy = 10; 2.10 2.11 +static void draw_time(GameState *gamestate, GameInfo *gameinfo) { 2.12 + if (gameinfo->timecontrol) { 2.13 + // TODO: correct time display 2.14 + 2.15 + uint16_t whitem = gameinfo->time / 60; 2.16 + uint16_t whites = gameinfo->time % 60; 2.17 + uint16_t blackm = gameinfo->time / 60; 2.18 + uint16_t blacks = gameinfo->time % 60; 2.19 + 2.20 + mvprintw(boardy+4, boardx-1, 2.21 + "White time: %4" PRIu16 ":%02" PRIu16, whitem, whites); 2.22 + mvprintw(boardy+5, boardx-1, 2.23 + "Black time: %4" PRIu16 ":%02" PRIu16, blackm, blacks); 2.24 + } 2.25 +} 2.26 + 2.27 static void draw_board(GameState *gamestate) { 2.28 - 2.29 for (uint8_t y = 0 ; y < 8 ; y++) { 2.30 for (uint8_t x = 0 ; x < 8 ; x++) { 2.31 uint8_t col = gamestate->board[y][x] & COLOR_MASK; 2.32 @@ -134,13 +150,14 @@ 2.33 } 2.34 } 2.35 2.36 -static int domove_singlemachine(GameState *gamestate) { 2.37 +static int domove_singlemachine(GameState *gamestate, GameInfo *gameinfo) { 2.38 2.39 const size_t buflen = 8; 2.40 char movestr[buflen]; 2.41 2.42 int inputy = getmaxy(stdscr) - 6; 2.43 while (1) { 2.44 + draw_time(gamestate, gameinfo); 2.45 move(inputy, 0); 2.46 printw( 2.47 "Use chess notation to enter your move.\n" 2.48 @@ -148,45 +165,46 @@ 2.49 "Type your move: "); 2.50 clrtoeol(); 2.51 refresh(); 2.52 - getnstr(movestr, buflen); 2.53 - 2.54 - if (strncmp(movestr, "surr", buflen) == 0) { 2.55 - printw("%s surrendered!", 2.56 - gamestate->mycolor==WHITE?"White":"Black"); 2.57 - clrtoeol(); 2.58 - refresh(); 2.59 - return 1; 2.60 - } else if (strncmp(movestr, "remis", buflen) == 0) { 2.61 - printw("Game ends remis."); 2.62 - clrtoeol(); 2.63 - refresh(); 2.64 - return 1; 2.65 - } else { 2.66 - Move move; 2.67 - int eval_result = eval_move(gamestate, movestr, &move); 2.68 - switch (eval_result) { 2.69 - case VALID_MOVE_SYNTAX: 2.70 - if (validate_move(gamestate, &move)) { 2.71 - apply_move(gamestate, &move); 2.72 - if (gamestate->checkmate) { 2.73 - printw("Checkmate!"); 2.74 - clrtoeol(); 2.75 - return 1; 2.76 - } else if (gamestate->stalemate) { 2.77 - printw("Stalemate!"); 2.78 - clrtoeol(); 2.79 - return 1; 2.80 + 2.81 + if (asyncgetnstr(movestr, buflen)) { 2.82 + if (strncmp(movestr, "surr", buflen) == 0) { 2.83 + printw("%s surrendered!", 2.84 + gamestate->mycolor==WHITE?"White":"Black"); 2.85 + clrtoeol(); 2.86 + refresh(); 2.87 + return 1; 2.88 + } else if (strncmp(movestr, "remis", buflen) == 0) { 2.89 + printw("Game ends remis."); 2.90 + clrtoeol(); 2.91 + refresh(); 2.92 + return 1; 2.93 + } else { 2.94 + Move move; 2.95 + int eval_result = eval_move(gamestate, movestr, &move); 2.96 + switch (eval_result) { 2.97 + case VALID_MOVE_SYNTAX: 2.98 + if (validate_move(gamestate, &move)) { 2.99 + apply_move(gamestate, &move); 2.100 + if (gamestate->checkmate) { 2.101 + printw("Checkmate!"); 2.102 + clrtoeol(); 2.103 + return 1; 2.104 + } else if (gamestate->stalemate) { 2.105 + printw("Stalemate!"); 2.106 + clrtoeol(); 2.107 + return 1; 2.108 + } else { 2.109 + return 0; 2.110 + } 2.111 } else { 2.112 - return 0; 2.113 + printw("Invalid move."); 2.114 } 2.115 - } else { 2.116 - printw("Invalid move."); 2.117 + break; 2.118 + default: 2.119 + eval_move_failed_msg(eval_result); 2.120 } 2.121 - break; 2.122 - default: 2.123 - eval_move_failed_msg(eval_result); 2.124 + clrtoeol(); 2.125 } 2.126 - clrtoeol(); 2.127 } 2.128 } 2.129 } 2.130 @@ -346,12 +364,12 @@ 2.131 memset(&gamestate, 0, sizeof(GameState)); 2.132 init_board(&gamestate); 2.133 gamestate.mycolor = WHITE; 2.134 - // TODO: time limit 2.135 + 2.136 _Bool running; 2.137 do { 2.138 clear(); 2.139 draw_board(&gamestate); 2.140 - running = !domove_singlemachine(&gamestate); 2.141 + running = !domove_singlemachine(&gamestate, &(settings->gameinfo)); 2.142 gamestate.mycolor = opponent_color(gamestate.mycolor); 2.143 } while (running); 2.144 move(0,0);
3.1 --- a/src/input.c Mon Apr 07 14:08:57 2014 +0200 3.2 +++ b/src/input.c Mon Apr 07 17:39:46 2014 +0200 3.3 @@ -28,7 +28,6 @@ 3.4 */ 3.5 3.6 #include "input.h" 3.7 -#include <ncurses.h> 3.8 3.9 void init_colorpairs() { 3.10 init_pair(COL_YB, COLOR_YELLOW, COLOR_BLUE); 3.11 @@ -48,3 +47,52 @@ 3.12 3.13 return ch == 'y'; 3.14 } 3.15 + 3.16 +/** 3.17 + * Asynchronous variant of getnstr(). 3.18 + * 3.19 + * Needs halfdelay mode enabled! 3.20 + * 3.21 + * Warning: you must not call this function for reading into two separate 3.22 + * buffers at the same time. 3.23 + * 3.24 + * Attention: the first byte of the buffer must be zero at the first call, so 3.25 + * the buffer pointer is initialized correctly. 3.26 + * 3.27 + * @param w the window 3.28 + * @param y the window y position 3.29 + * @param x the window x position 3.30 + * @param str the buffer for the read string 3.31 + * @param len the length of the buffer 3.32 + * @return 0 if reading is in progress and 1 when a complete line is read 3.33 + */ 3.34 +int mvwasyncgetnstr(WINDOW* w, int y, int x, char *str, size_t len) { 3.35 + static size_t pos = 0; 3.36 + 3.37 + if (*str == '\0') { 3.38 + pos = 0; 3.39 + } 3.40 + 3.41 + mvwaddstr(w,y, x, str); 3.42 + wrefresh(w); 3.43 + int c = wgetch(w); 3.44 + 3.45 + if (c != ERR) { 3.46 + switch (c) { 3.47 + case '\n': 3.48 + str[pos] = '\0'; 3.49 + pos = 0; 3.50 + return 1; 3.51 + case KEY_BACKSPACE: 3.52 + case KEY_LEFT: 3.53 + str[--pos] = '\0'; 3.54 + break; 3.55 + default: 3.56 + if (c < 255 && pos < len-1) { 3.57 + str[pos++] = (char) c; 3.58 + } 3.59 + } 3.60 + } 3.61 + 3.62 + return 0; 3.63 +}
4.1 --- a/src/input.h Mon Apr 07 14:08:57 2014 +0200 4.2 +++ b/src/input.h Mon Apr 07 17:39:46 2014 +0200 4.3 @@ -30,6 +30,9 @@ 4.4 #ifndef INPUT_H 4.5 #define INPUT_H 4.6 4.7 +#include <stdlib.h> 4.8 +#include <ncurses.h> 4.9 + 4.10 #ifdef __cplusplus 4.11 extern "C" { 4.12 #endif 4.13 @@ -42,6 +45,11 @@ 4.14 4.15 int prompt_yesno(char *msg); 4.16 4.17 +int mvwasyncgetnstr(WINDOW* w, int y, int x, char *str, size_t len); 4.18 +#define mvasyncgetnstr(y,x,str,len) mvwasyncgetnstr(stdscr,y,x,str,len) 4.19 +#define asyncgetnstr(str,len) mvwasyncgetnstr(stdscr, stdscr->_cury, \ 4.20 + stdscr->_curx, str, len) 4.21 + 4.22 4.23 #ifdef __cplusplus 4.24 }
5.1 --- a/src/main.c Mon Apr 07 14:08:57 2014 +0200 5.2 +++ b/src/main.c Mon Apr 07 17:39:46 2014 +0200 5.3 @@ -59,11 +59,13 @@ 5.4 timeunit = 1; 5.5 } 5.6 5.7 - if ((time = strtoul(optarg, &valid, 10)) > TIME_MAX 5.8 + if ((time = strtoul(optarg, &valid, 10))*timeunit > UINT16_MAX 5.9 || *valid != '\0') { 5.10 - fprintf(stderr, "Specified time is invalid (%s)\n", optarg); 5.11 + fprintf(stderr, "Specified time is invalid (%s)" 5.12 + "- Maximum: 65535 seconds (1092 minutes)\n", optarg); 5.13 return 1; 5.14 } else { 5.15 + settings->gameinfo.timecontrol = 1; 5.16 if (opt=='t') { 5.17 settings->gameinfo.time = timeunit * time; 5.18 } else { 5.19 @@ -108,7 +110,7 @@ 5.20 return settings; 5.21 } 5.22 5.23 -void dump_gameinfo(Gameinfo *gameinfo) { 5.24 +void dump_gameinfo(GameInfo *gameinfo) { 5.25 int serverwhite = gameinfo->servercolor == WHITE; 5.26 attron(A_UNDERLINE); 5.27 printw("Game details\n"); 5.28 @@ -116,7 +118,7 @@ 5.29 printw(" Server: %s\n Client: %s\n", 5.30 serverwhite?"white":"black", serverwhite?"black":"White" 5.31 ); 5.32 - if (gameinfo->time > 0) { 5.33 + if (gameinfo->timecontrol) { 5.34 if (gameinfo->time % 60) { 5.35 printw(" Time limit: %ds + %ds\n", 5.36 gameinfo->time, gameinfo->addtime); 5.37 @@ -163,7 +165,7 @@ 5.38 return EXIT_SUCCESS; 5.39 } 5.40 initscr(); 5.41 - cbreak(); 5.42 + halfdelay(10); 5.43 keypad(stdscr, TRUE); 5.44 if (has_colors()) { 5.45 start_color();
6.1 --- a/src/server.c Mon Apr 07 14:08:57 2014 +0200 6.2 +++ b/src/server.c Mon Apr 07 17:39:46 2014 +0200 6.3 @@ -77,7 +77,7 @@ 6.4 6.5 int fd = server.client->fd; 6.6 net_send_data(fd, NETCODE_GAMEINFO, 6.7 - &(settings->gameinfo), sizeof(Gameinfo)); 6.8 + &(settings->gameinfo), sizeof(GameInfo)); 6.9 printw("\rClient connected - awaiting challenge acceptance..."); 6.10 refresh(); 6.11 int code = net_recieve_code(fd);
7.1 --- a/src/terminal-chess.h Mon Apr 07 14:08:57 2014 +0200 7.2 +++ b/src/terminal-chess.h Mon Apr 07 17:39:46 2014 +0200 7.3 @@ -31,6 +31,7 @@ 7.4 #include <stdio.h> 7.5 #include <ncurses.h> 7.6 #include "network.h" 7.7 +#include "chess/rules.h" 7.8 7.9 #ifndef TERMINAL_CHESS_H 7.10 #define TERMINAL_CHESS_H 7.11 @@ -39,16 +40,8 @@ 7.12 extern "C" { 7.13 #endif 7.14 7.15 -#define TIME_MAX UINT16_MAX 7.16 - 7.17 typedef struct { 7.18 - uint8_t servercolor; 7.19 - uint16_t time; 7.20 - uint16_t addtime; 7.21 -} Gameinfo; 7.22 - 7.23 -typedef struct { 7.24 - Gameinfo gameinfo; 7.25 + GameInfo gameinfo; 7.26 char* port; 7.27 char* serverhost; /* NULL, if we are about to start a server */ 7.28 _Bool printhelp; 7.29 @@ -57,7 +50,7 @@ 7.30 7.31 #define is_server(settings) !((settings)->serverhost) 7.32 7.33 -void dump_gameinfo(Gameinfo *gameinfo); 7.34 +void dump_gameinfo(GameInfo *gameinfo); 7.35 7.36 int server_run(Settings* settings); 7.37 int client_run(Settings* settings);