implemented chess board and remis/surrender messages

Wed, 19 Mar 2014 15:36:54 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 19 Mar 2014 15:36:54 +0100
changeset 7
41468077b5bb
parent 6
daaf6e5b3501
child 8
52d742aee695

implemented chess board and remis/surrender messages

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/input.c file | annotate | diff | comparison | revisions
src/input.h file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/network.c file | annotate | diff | comparison | revisions
src/network.h file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
--- a/src/client.c	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/client.c	Wed Mar 19 15:36:54 2014 +0100
@@ -77,8 +77,7 @@
         net_recieve_data(server.fd, &(settings->gameinfo),
             sizeof(settings->gameinfo));
         dump_gameinfo(&(settings->gameinfo));
-        printw("Accept challenge (y/n)? ");
-        if (prompt_yesno()) {
+        if (prompt_yesno("Accept challenge")) {
             net_send_code(server.fd, NETCODE_ACCEPT);
             game_start(settings, server.fd);
         } else {
--- a/src/game.c	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/game.c	Wed Mar 19 15:36:54 2014 +0100
@@ -28,7 +28,153 @@
  */
 
 #include "game.h"
+#include "input.h"
+#include <ncurses.h>
+#include <string.h>
+
+static const uint8_t boardx = 10, boardy = 10;
+
+static void draw_board(Board board) {
+    
+    for (uint8_t y = 0 ; y < 8 ; y++) {
+        for (uint8_t x = 0 ; x < 8 ; x++) {
+            uint8_t col = board[y][x] & COLOR_MASK;
+            uint8_t piece = board[y][x] & PIECE_MASK;
+            char piecec = ' ';
+            switch (piece) {
+                case PAWN: piecec = 'P'; break;
+                case ROOK: piecec = 'R'; break;
+                case KNIGHT: piecec = 'N'; break;
+                case BISHOP: piecec = 'B'; break;
+                case QUEEN: piecec = 'Q'; break;
+                case KING: piecec = 'K'; break;
+            }
+            
+            attrset((col == WHITE ? A_BOLD : A_DIM) |
+                COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
+            
+            mvaddch(boardy-y, boardx+x*3, ' ');
+            mvaddch(boardy-y, boardx+x*3+1, piecec);
+            mvaddch(boardy-y, boardx+x*3+2, ' ');
+        }
+    }
+    
+    attrset(A_NORMAL);
+    for (uint8_t i = 0 ; i < 8 ; i++) {
+        mvaddch(boardy+1, boardx+i*3+1, 'a'+i);
+        mvaddch(boardy-i, boardx-2, '1'+i);
+    }
+}
+
+static int sendmove(int opponent) {
+    const size_t buflen = 8;
+    char move[buflen];
+    _Bool remisrejected = FALSE;
+    
+    while (1) {
+        move(boardy+3, 0);
+        if (remisrejected) {
+            printw(
+                "Use chess notation to enter your move.\n"
+                "Remis offer rejected - type 'surr' to surrender.      \n\n"
+                "Type your move: ");
+        } else {
+            printw(
+                "Use chess notation to enter your move.\n"
+                "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
+                "Type your move: ");
+        }
+        clrtoeol();
+        refresh();
+        getnstr(move, buflen);
+
+        if (strncmp(move, "surr", buflen) == 0) {
+            printw("You surrendered!");
+            net_send_code(opponent, NETCODE_SURRENDER);
+            return 1;
+        } else if (strncmp(move, "remis", buflen) == 0) {
+            if (!remisrejected) {
+                net_send_code(opponent, NETCODE_REMIS);
+                printw("Remis offer sent - waiting for acceptance...");
+                refresh();
+                if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
+                    printw("\rRemis accepted!");
+                    clrtoeol();
+                    return 1;
+                } else {
+                    remisrejected = TRUE;
+                }
+            }
+        } else {
+            // TODO: validate move syntactically
+            // TODO: send move and await acceptance
+        }
+    }
+}
+
+static int recvmove(int opponent) {
+    
+    while (1) {
+        move(boardy+3, 0);
+        printw("Awaiting opponent move...");
+        clrtoeol();
+        refresh();
+
+        // TODO: nonblocking
+        uint32_t code = net_recieve_code(opponent);
+        switch (code) {
+            case NETCODE_SURRENDER:
+                printw("\rYour opponent surrendered!");
+                clrtoeol();
+                return 1;
+            case NETCODE_REMIS:
+                if (prompt_yesno(
+                    "\rYour opponent offers remis - do you accept")) {
+                    printw("\rRemis accepted!");
+                    clrtoeol();
+                    net_send_code(opponent, NETCODE_ACCEPT);
+                    return 1;
+                } else {
+                    net_send_code(opponent, NETCODE_DECLINE);
+                }
+                break;
+            case NETCODE_MOVE:
+                // TODO: receive move
+                // TODO: validate move and accept/reject
+                return 0;
+        }
+    }
+}
 
 void game_start(Settings *settings, int opponent) {
+    _Bool myturn = is_server(settings) ==
+        (settings->gameinfo.servercolor == WHITE);
+    _Bool running;
     
+    Board board = {
+        {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
+        {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
+        {0,     0,       0,       0,      0,     0,       0,       0},
+        {0,     0,       0,       0,      0,     0,       0,       0},
+        {0,     0,       0,       0,      0,     0,       0,       0},
+        {0,     0,       0,       0,      0,     0,       0,       0},
+        {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
+        {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
+    };
+    
+    do {
+        clear();
+        draw_board(board);
+        if (myturn) {
+            running = !sendmove(opponent);
+        } else {
+            running = !recvmove(opponent);
+            flushinp(); // flush any input the user hacked in while waiting
+        }
+        myturn ^= 1;
+    }  while (running);
+    
+    mvaddstr(getmaxy(tchess_window)-1, 0,
+        "Game has ended. Press any key to leave...");
+    getch();
 }
--- a/src/game.h	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/game.h	Wed Mar 19 15:36:54 2014 +0100
@@ -31,11 +31,40 @@
 #define	GAME_H
 
 #include "terminal-chess.h"
+#include <stdint.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
+#define PIECE_MASK 0x0F
+#define COLOR_MASK 0xF0
+
+#define WHITE 0x10
+#define BLACK 0x20
+
+#define PAWN   0x01
+#define ROOK   0x02
+#define KNIGHT 0x03
+#define BISHOP 0x04
+#define QUEEN  0x05
+#define KING   0x06
+
+#define WPAWN   (WHITE|PAWN)
+#define WROOK   (WHITE|ROOK)
+#define WKNIGHT (WHITE|KNIGHT)
+#define WBISHOP (WHITE|BISHOP)
+#define WQUEEN  (WHITE|QUEEN)
+#define WKING   (WHITE|KING)
+#define BPAWN   (BLACK|PAWN)
+#define BROOK   (BLACK|ROOK)
+#define BKNIGHT (BLACK|KNIGHT)
+#define BBISHOP (BLACK|BISHOP)
+#define BQUEEN  (BLACK|QUEEN)
+#define BKING   (BLACK|KING)
+
+typedef uint8_t Board[8][8];
+
 void game_start(Settings *settings, int opponent);
 
 #ifdef	__cplusplus
--- a/src/input.c	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/input.c	Wed Mar 19 15:36:54 2014 +0100
@@ -30,7 +30,15 @@
 #include "input.h"
 #include <ncurses.h>
 
-int prompt_yesno() {
+void init_colorpairs() {
+    init_pair(COL_YB, COLOR_YELLOW, COLOR_BLUE);
+    init_pair(COL_BW, COLOR_BLACK, COLOR_WHITE);
+    init_pair(COL_WB, COLOR_WHITE, COLOR_BLACK);
+}
+
+int prompt_yesno(char *msg) {
+    printw("%s (y/n)? ", msg);
+    refresh();
     noecho();
     int ch;
     do {
--- a/src/input.h	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/input.h	Wed Mar 19 15:36:54 2014 +0100
@@ -34,7 +34,13 @@
 extern "C" {
 #endif
 
-int prompt_yesno();
+#define COL_YB 1
+#define COL_BW 2
+#define COL_WB 3
+
+void init_colorpairs();
+
+int prompt_yesno(char *msg);
 
 
 #ifdef	__cplusplus
--- a/src/main.c	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/main.c	Wed Mar 19 15:36:54 2014 +0100
@@ -28,9 +28,11 @@
  */
 
 #include "terminal-chess.h"
+#include "game.h"
+#include "input.h"
 #include <string.h>
 #include <time.h>
-#include <ncurses.h>
+#include <getopt.h>
 
 int get_settings(int argc, char **argv, Settings *settings) {
     char *valid;
@@ -44,7 +46,7 @@
             settings->gameinfo.servercolor = BLACK;
             break;
         case 'r':
-            settings->gameinfo.servercolor = (rand()>>5) & 1 ? WHITE : BLACK;
+            settings->gameinfo.servercolor = rand() & 1 ? WHITE : BLACK;
             break;
         case 't':
         case 'a':
@@ -125,11 +127,7 @@
     refresh();
 }
 
-static WINDOW* window;
-
 void leavescr() {
-    mvprintw(getmaxy(window)-1, 0, "Leaving terminal-chess. Press any key...");
-    getch();
     endwin();
 }
 
@@ -162,9 +160,17 @@
         );
         return EXIT_SUCCESS;
     }
-    
-    window = initscr();
+    tchess_window = initscr();
     cbreak();
+    if (has_colors()) {
+        start_color();
+        init_colorpairs();
+        bkgd(COLOR_PAIR(COL_YB));
+    } else {
+        fprintf(stderr, "Non-colored terminals are not supported yet.");
+        endwin();
+        return EXIT_FAILURE;
+    }
     atexit(leavescr);
     
     return is_server(&settings) ? server_run(&settings) : client_run(&settings);
--- a/src/network.c	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/network.c	Wed Mar 19 15:36:54 2014 +0100
@@ -122,7 +122,7 @@
     send(socket, data, len, 0);
 }
 
-int net_recieve_code(int socket) {
+uint32_t net_recieve_code(int socket) {
     uint32_t code;
     recv(socket, &code, sizeof(uint32_t), 0);
     return ntohl(code);
--- a/src/network.h	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/network.h	Wed Mar 19 15:36:54 2014 +0100
@@ -40,8 +40,11 @@
 #define NETCODE_ACCEPT 0x00
 #define NETCODE_DECLINE 0x01
 #define NETCODE_GAMEINFO 0x10
+#define NETCODE_MOVE 0x20
+#define NETCODE_SURRENDER 0x21
+#define NETCODE_REMIS 0x22
     
-#define NETCODE_VERSION 1
+#define NETCODE_VERSION 3
 
 typedef struct {
     int fd; /* -1, if we are the client */
@@ -64,7 +67,7 @@
 
 void net_send_code(int socket, uint32_t code);
 void net_send_data(int socket, void *data, size_t len);
-int net_recieve_code(int socket);
+uint32_t net_recieve_code(int socket);
 void net_recieve_data(int socket, void *data, size_t len);
 
 
--- a/src/terminal-chess.h	Wed Mar 19 10:08:25 2014 +0100
+++ b/src/terminal-chess.h	Wed Mar 19 15:36:54 2014 +0100
@@ -29,7 +29,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <getopt.h>
+#include <ncurses.h>
 #include "network.h"
 
 #ifndef TERMINAL_CHESS_H
@@ -38,9 +38,9 @@
 #ifdef	__cplusplus
 extern "C" {
 #endif
-    
-#define WHITE 0
-#define BLACK 1
+
+WINDOW* tchess_window;
+
 #define TIME_MAX UINT16_MAX
     
 typedef struct {

mercurial