experimental async input for single machine mode

Mon, 07 Apr 2014 17:39:46 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 07 Apr 2014 17:39:46 +0200
changeset 30
a285ee393860
parent 29
c6a1ad6cf749
child 31
ed440bcd9740

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
--- a/src/chess/rules.h	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/chess/rules.h	Mon Apr 07 17:39:46 2014 +0200
@@ -87,6 +87,14 @@
     MoveList* next;
 };
 
+    
+typedef struct {
+    uint8_t servercolor;
+    _Bool timecontrol;
+    uint16_t time;
+    uint16_t addtime;
+} GameInfo;
+
 typedef struct {
     Board board;
     uint8_t mycolor;
--- a/src/game.c	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/game.c	Mon Apr 07 17:39:46 2014 +0200
@@ -32,11 +32,27 @@
 #include "input.h"
 #include <ncurses.h>
 #include <string.h>
+#include <inttypes.h>
 
 static const uint8_t boardx = 10, boardy = 10;
 
+static void draw_time(GameState *gamestate, GameInfo *gameinfo) {
+    if (gameinfo->timecontrol) {
+        // TODO: correct time display
+        
+        uint16_t whitem = gameinfo->time / 60;
+        uint16_t whites = gameinfo->time % 60;
+        uint16_t blackm = gameinfo->time / 60;
+        uint16_t blacks = gameinfo->time % 60;
+        
+        mvprintw(boardy+4, boardx-1,
+            "White time: %4" PRIu16 ":%02" PRIu16, whitem, whites);
+        mvprintw(boardy+5, boardx-1,
+            "Black time: %4" PRIu16 ":%02" PRIu16, blackm, blacks);
+    }
+}
+
 static void draw_board(GameState *gamestate) {
-    
     for (uint8_t y = 0 ; y < 8 ; y++) {
         for (uint8_t x = 0 ; x < 8 ; x++) {
             uint8_t col = gamestate->board[y][x] & COLOR_MASK;
@@ -134,13 +150,14 @@
     }
 }
 
-static int domove_singlemachine(GameState *gamestate) {
+static int domove_singlemachine(GameState *gamestate, GameInfo *gameinfo) {
     
     const size_t buflen = 8;
     char movestr[buflen];
     
     int inputy = getmaxy(stdscr) - 6;
     while (1) {
+        draw_time(gamestate, gameinfo);
         move(inputy, 0);
         printw(
             "Use chess notation to enter your move.\n"
@@ -148,45 +165,46 @@
             "Type your move: ");
         clrtoeol();
         refresh();
-        getnstr(movestr, buflen);
-
-        if (strncmp(movestr, "surr", buflen) == 0) {
-            printw("%s surrendered!",
-                gamestate->mycolor==WHITE?"White":"Black");
-            clrtoeol();
-            refresh();
-            return 1;
-        } else if (strncmp(movestr, "remis", buflen) == 0) {
-            printw("Game ends remis.");
-            clrtoeol();
-            refresh();
-            return 1;
-        } else {
-            Move move;
-            int eval_result = eval_move(gamestate, movestr, &move);
-            switch (eval_result) {
-            case VALID_MOVE_SYNTAX:
-                if (validate_move(gamestate, &move)) {
-                    apply_move(gamestate, &move);
-                    if (gamestate->checkmate) {
-                        printw("Checkmate!");
-                        clrtoeol();
-                        return 1;
-                    } else if (gamestate->stalemate) {
-                        printw("Stalemate!");
-                        clrtoeol();
-                        return 1;
+        
+        if (asyncgetnstr(movestr, buflen)) {
+            if (strncmp(movestr, "surr", buflen) == 0) {
+                printw("%s surrendered!",
+                    gamestate->mycolor==WHITE?"White":"Black");
+                clrtoeol();
+                refresh();
+                return 1;
+            } else if (strncmp(movestr, "remis", buflen) == 0) {
+                printw("Game ends remis.");
+                clrtoeol();
+                refresh();
+                return 1;
+            } else {
+                Move move;
+                int eval_result = eval_move(gamestate, movestr, &move);
+                switch (eval_result) {
+                case VALID_MOVE_SYNTAX:
+                    if (validate_move(gamestate, &move)) {
+                        apply_move(gamestate, &move);
+                        if (gamestate->checkmate) {
+                            printw("Checkmate!");
+                            clrtoeol();
+                            return 1;
+                        } else if (gamestate->stalemate) {
+                            printw("Stalemate!");
+                            clrtoeol();
+                            return 1;
+                        } else {
+                            return 0;
+                        }
                     } else {
-                        return 0;
+                        printw("Invalid move.");
                     }
-                } else {
-                    printw("Invalid move.");
+                    break;
+                default:
+                    eval_move_failed_msg(eval_result);
                 }
-                break;
-            default:
-                eval_move_failed_msg(eval_result);
+                clrtoeol();
             }
-            clrtoeol();
         }
     }
 }
@@ -346,12 +364,12 @@
     memset(&gamestate, 0, sizeof(GameState));
     init_board(&gamestate);
     gamestate.mycolor = WHITE;
-    // TODO: time limit
+
     _Bool running;
     do {
         clear();
         draw_board(&gamestate);
-        running = !domove_singlemachine(&gamestate);
+        running = !domove_singlemachine(&gamestate, &(settings->gameinfo));
         gamestate.mycolor = opponent_color(gamestate.mycolor);
     }  while (running);
     move(0,0);
--- a/src/input.c	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/input.c	Mon Apr 07 17:39:46 2014 +0200
@@ -28,7 +28,6 @@
  */
 
 #include "input.h"
-#include <ncurses.h>
 
 void init_colorpairs() {
     init_pair(COL_YB, COLOR_YELLOW, COLOR_BLUE);
@@ -48,3 +47,52 @@
     
     return ch == 'y';
 }
+
+/**
+ * Asynchronous variant of getnstr().
+ * 
+ * Needs halfdelay mode enabled!
+ * 
+ * Warning: you must not call this function for reading into two separate
+ * buffers at the same time.
+ * 
+ * Attention: the first byte of the buffer must be zero at the first call, so
+ * the buffer pointer is initialized correctly.
+ * 
+ * @param w the window
+ * @param y the window y position
+ * @param x the window x position
+ * @param str the buffer for the read string
+ * @param len the length of the buffer
+ * @return 0 if reading is in progress and 1 when a complete line is read
+ */
+int mvwasyncgetnstr(WINDOW* w, int y, int x, char *str, size_t len) {
+    static size_t pos = 0;
+    
+    if (*str == '\0') {
+        pos = 0;
+    }
+    
+    mvwaddstr(w,y, x, str);
+    wrefresh(w);
+    int c = wgetch(w);
+
+    if (c != ERR) {
+        switch (c) {
+        case '\n':
+            str[pos] = '\0';
+            pos = 0;
+            return 1;
+        case KEY_BACKSPACE:
+        case KEY_LEFT:
+            str[--pos] = '\0';
+            break;
+        default:
+            if (c < 255 && pos < len-1) {
+                str[pos++] = (char) c;
+            }
+        }
+    }
+    
+    return 0;
+}
--- a/src/input.h	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/input.h	Mon Apr 07 17:39:46 2014 +0200
@@ -30,6 +30,9 @@
 #ifndef INPUT_H
 #define	INPUT_H
 
+#include <stdlib.h>
+#include <ncurses.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -42,6 +45,11 @@
 
 int prompt_yesno(char *msg);
 
+int mvwasyncgetnstr(WINDOW* w, int y, int x, char *str, size_t len);
+#define mvasyncgetnstr(y,x,str,len) mvwasyncgetnstr(stdscr,y,x,str,len)
+#define asyncgetnstr(str,len) mvwasyncgetnstr(stdscr, stdscr->_cury, \
+    stdscr->_curx, str, len)
+
 
 #ifdef	__cplusplus
 }
--- a/src/main.c	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/main.c	Mon Apr 07 17:39:46 2014 +0200
@@ -59,11 +59,13 @@
                 timeunit = 1;
             }
             
-            if ((time = strtoul(optarg, &valid, 10)) > TIME_MAX
+            if ((time = strtoul(optarg, &valid, 10))*timeunit > UINT16_MAX
                 || *valid != '\0') {
-                fprintf(stderr, "Specified time is invalid (%s)\n", optarg);
+                fprintf(stderr, "Specified time is invalid (%s)"
+                    "- Maximum: 65535 seconds (1092 minutes)\n", optarg);
                 return 1;
             } else {
+                settings->gameinfo.timecontrol = 1;
                 if (opt=='t') {
                     settings->gameinfo.time = timeunit * time;
                 } else {
@@ -108,7 +110,7 @@
     return settings;
 }
 
-void dump_gameinfo(Gameinfo *gameinfo) {
+void dump_gameinfo(GameInfo *gameinfo) {
     int serverwhite = gameinfo->servercolor == WHITE;
     attron(A_UNDERLINE);
     printw("Game details\n");
@@ -116,7 +118,7 @@
     printw("  Server:     %s\n  Client:     %s\n",
         serverwhite?"white":"black", serverwhite?"black":"White"
     );
-    if (gameinfo->time > 0) {
+    if (gameinfo->timecontrol) {
         if (gameinfo->time % 60) {
             printw("  Time limit: %ds + %ds\n",
                 gameinfo->time, gameinfo->addtime);
@@ -163,7 +165,7 @@
         return EXIT_SUCCESS;
     }    
     initscr();
-    cbreak();
+    halfdelay(10);
     keypad(stdscr, TRUE);
     if (has_colors()) {
         start_color();
--- a/src/server.c	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/server.c	Mon Apr 07 17:39:46 2014 +0200
@@ -77,7 +77,7 @@
 
     int fd = server.client->fd;
     net_send_data(fd, NETCODE_GAMEINFO,
-        &(settings->gameinfo), sizeof(Gameinfo));
+        &(settings->gameinfo), sizeof(GameInfo));
     printw("\rClient connected - awaiting challenge acceptance...");
     refresh();
     int code = net_recieve_code(fd);
--- a/src/terminal-chess.h	Mon Apr 07 14:08:57 2014 +0200
+++ b/src/terminal-chess.h	Mon Apr 07 17:39:46 2014 +0200
@@ -31,6 +31,7 @@
 #include <stdio.h>
 #include <ncurses.h>
 #include "network.h"
+#include "chess/rules.h"
 
 #ifndef TERMINAL_CHESS_H
 #define	TERMINAL_CHESS_H
@@ -39,16 +40,8 @@
 extern "C" {
 #endif
 
-#define TIME_MAX UINT16_MAX
-    
 typedef struct {
-    uint8_t servercolor;
-    uint16_t time;
-    uint16_t addtime;
-} Gameinfo;
-
-typedef struct {
-    Gameinfo gameinfo;
+    GameInfo gameinfo;
     char* port;
     char* serverhost; /* NULL, if we are about to start a server */
     _Bool printhelp;
@@ -57,7 +50,7 @@
 
 #define is_server(settings) !((settings)->serverhost)
 
-void dump_gameinfo(Gameinfo *gameinfo);
+void dump_gameinfo(GameInfo *gameinfo);
 
 int server_run(Settings* settings);
 int client_run(Settings* settings);

mercurial