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
     1.1 --- a/src/client.c	Wed Mar 19 10:08:25 2014 +0100
     1.2 +++ b/src/client.c	Wed Mar 19 15:36:54 2014 +0100
     1.3 @@ -77,8 +77,7 @@
     1.4          net_recieve_data(server.fd, &(settings->gameinfo),
     1.5              sizeof(settings->gameinfo));
     1.6          dump_gameinfo(&(settings->gameinfo));
     1.7 -        printw("Accept challenge (y/n)? ");
     1.8 -        if (prompt_yesno()) {
     1.9 +        if (prompt_yesno("Accept challenge")) {
    1.10              net_send_code(server.fd, NETCODE_ACCEPT);
    1.11              game_start(settings, server.fd);
    1.12          } else {
     2.1 --- a/src/game.c	Wed Mar 19 10:08:25 2014 +0100
     2.2 +++ b/src/game.c	Wed Mar 19 15:36:54 2014 +0100
     2.3 @@ -28,7 +28,153 @@
     2.4   */
     2.5  
     2.6  #include "game.h"
     2.7 +#include "input.h"
     2.8 +#include <ncurses.h>
     2.9 +#include <string.h>
    2.10 +
    2.11 +static const uint8_t boardx = 10, boardy = 10;
    2.12 +
    2.13 +static void draw_board(Board board) {
    2.14 +    
    2.15 +    for (uint8_t y = 0 ; y < 8 ; y++) {
    2.16 +        for (uint8_t x = 0 ; x < 8 ; x++) {
    2.17 +            uint8_t col = board[y][x] & COLOR_MASK;
    2.18 +            uint8_t piece = board[y][x] & PIECE_MASK;
    2.19 +            char piecec = ' ';
    2.20 +            switch (piece) {
    2.21 +                case PAWN: piecec = 'P'; break;
    2.22 +                case ROOK: piecec = 'R'; break;
    2.23 +                case KNIGHT: piecec = 'N'; break;
    2.24 +                case BISHOP: piecec = 'B'; break;
    2.25 +                case QUEEN: piecec = 'Q'; break;
    2.26 +                case KING: piecec = 'K'; break;
    2.27 +            }
    2.28 +            
    2.29 +            attrset((col == WHITE ? A_BOLD : A_DIM) |
    2.30 +                COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
    2.31 +            
    2.32 +            mvaddch(boardy-y, boardx+x*3, ' ');
    2.33 +            mvaddch(boardy-y, boardx+x*3+1, piecec);
    2.34 +            mvaddch(boardy-y, boardx+x*3+2, ' ');
    2.35 +        }
    2.36 +    }
    2.37 +    
    2.38 +    attrset(A_NORMAL);
    2.39 +    for (uint8_t i = 0 ; i < 8 ; i++) {
    2.40 +        mvaddch(boardy+1, boardx+i*3+1, 'a'+i);
    2.41 +        mvaddch(boardy-i, boardx-2, '1'+i);
    2.42 +    }
    2.43 +}
    2.44 +
    2.45 +static int sendmove(int opponent) {
    2.46 +    const size_t buflen = 8;
    2.47 +    char move[buflen];
    2.48 +    _Bool remisrejected = FALSE;
    2.49 +    
    2.50 +    while (1) {
    2.51 +        move(boardy+3, 0);
    2.52 +        if (remisrejected) {
    2.53 +            printw(
    2.54 +                "Use chess notation to enter your move.\n"
    2.55 +                "Remis offer rejected - type 'surr' to surrender.      \n\n"
    2.56 +                "Type your move: ");
    2.57 +        } else {
    2.58 +            printw(
    2.59 +                "Use chess notation to enter your move.\n"
    2.60 +                "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
    2.61 +                "Type your move: ");
    2.62 +        }
    2.63 +        clrtoeol();
    2.64 +        refresh();
    2.65 +        getnstr(move, buflen);
    2.66 +
    2.67 +        if (strncmp(move, "surr", buflen) == 0) {
    2.68 +            printw("You surrendered!");
    2.69 +            net_send_code(opponent, NETCODE_SURRENDER);
    2.70 +            return 1;
    2.71 +        } else if (strncmp(move, "remis", buflen) == 0) {
    2.72 +            if (!remisrejected) {
    2.73 +                net_send_code(opponent, NETCODE_REMIS);
    2.74 +                printw("Remis offer sent - waiting for acceptance...");
    2.75 +                refresh();
    2.76 +                if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
    2.77 +                    printw("\rRemis accepted!");
    2.78 +                    clrtoeol();
    2.79 +                    return 1;
    2.80 +                } else {
    2.81 +                    remisrejected = TRUE;
    2.82 +                }
    2.83 +            }
    2.84 +        } else {
    2.85 +            // TODO: validate move syntactically
    2.86 +            // TODO: send move and await acceptance
    2.87 +        }
    2.88 +    }
    2.89 +}
    2.90 +
    2.91 +static int recvmove(int opponent) {
    2.92 +    
    2.93 +    while (1) {
    2.94 +        move(boardy+3, 0);
    2.95 +        printw("Awaiting opponent move...");
    2.96 +        clrtoeol();
    2.97 +        refresh();
    2.98 +
    2.99 +        // TODO: nonblocking
   2.100 +        uint32_t code = net_recieve_code(opponent);
   2.101 +        switch (code) {
   2.102 +            case NETCODE_SURRENDER:
   2.103 +                printw("\rYour opponent surrendered!");
   2.104 +                clrtoeol();
   2.105 +                return 1;
   2.106 +            case NETCODE_REMIS:
   2.107 +                if (prompt_yesno(
   2.108 +                    "\rYour opponent offers remis - do you accept")) {
   2.109 +                    printw("\rRemis accepted!");
   2.110 +                    clrtoeol();
   2.111 +                    net_send_code(opponent, NETCODE_ACCEPT);
   2.112 +                    return 1;
   2.113 +                } else {
   2.114 +                    net_send_code(opponent, NETCODE_DECLINE);
   2.115 +                }
   2.116 +                break;
   2.117 +            case NETCODE_MOVE:
   2.118 +                // TODO: receive move
   2.119 +                // TODO: validate move and accept/reject
   2.120 +                return 0;
   2.121 +        }
   2.122 +    }
   2.123 +}
   2.124  
   2.125  void game_start(Settings *settings, int opponent) {
   2.126 +    _Bool myturn = is_server(settings) ==
   2.127 +        (settings->gameinfo.servercolor == WHITE);
   2.128 +    _Bool running;
   2.129      
   2.130 +    Board board = {
   2.131 +        {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
   2.132 +        {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
   2.133 +        {0,     0,       0,       0,      0,     0,       0,       0},
   2.134 +        {0,     0,       0,       0,      0,     0,       0,       0},
   2.135 +        {0,     0,       0,       0,      0,     0,       0,       0},
   2.136 +        {0,     0,       0,       0,      0,     0,       0,       0},
   2.137 +        {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
   2.138 +        {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
   2.139 +    };
   2.140 +    
   2.141 +    do {
   2.142 +        clear();
   2.143 +        draw_board(board);
   2.144 +        if (myturn) {
   2.145 +            running = !sendmove(opponent);
   2.146 +        } else {
   2.147 +            running = !recvmove(opponent);
   2.148 +            flushinp(); // flush any input the user hacked in while waiting
   2.149 +        }
   2.150 +        myturn ^= 1;
   2.151 +    }  while (running);
   2.152 +    
   2.153 +    mvaddstr(getmaxy(tchess_window)-1, 0,
   2.154 +        "Game has ended. Press any key to leave...");
   2.155 +    getch();
   2.156  }
     3.1 --- a/src/game.h	Wed Mar 19 10:08:25 2014 +0100
     3.2 +++ b/src/game.h	Wed Mar 19 15:36:54 2014 +0100
     3.3 @@ -31,11 +31,40 @@
     3.4  #define	GAME_H
     3.5  
     3.6  #include "terminal-chess.h"
     3.7 +#include <stdint.h>
     3.8  
     3.9  #ifdef	__cplusplus
    3.10  extern "C" {
    3.11  #endif
    3.12  
    3.13 +#define PIECE_MASK 0x0F
    3.14 +#define COLOR_MASK 0xF0
    3.15 +
    3.16 +#define WHITE 0x10
    3.17 +#define BLACK 0x20
    3.18 +
    3.19 +#define PAWN   0x01
    3.20 +#define ROOK   0x02
    3.21 +#define KNIGHT 0x03
    3.22 +#define BISHOP 0x04
    3.23 +#define QUEEN  0x05
    3.24 +#define KING   0x06
    3.25 +
    3.26 +#define WPAWN   (WHITE|PAWN)
    3.27 +#define WROOK   (WHITE|ROOK)
    3.28 +#define WKNIGHT (WHITE|KNIGHT)
    3.29 +#define WBISHOP (WHITE|BISHOP)
    3.30 +#define WQUEEN  (WHITE|QUEEN)
    3.31 +#define WKING   (WHITE|KING)
    3.32 +#define BPAWN   (BLACK|PAWN)
    3.33 +#define BROOK   (BLACK|ROOK)
    3.34 +#define BKNIGHT (BLACK|KNIGHT)
    3.35 +#define BBISHOP (BLACK|BISHOP)
    3.36 +#define BQUEEN  (BLACK|QUEEN)
    3.37 +#define BKING   (BLACK|KING)
    3.38 +
    3.39 +typedef uint8_t Board[8][8];
    3.40 +
    3.41  void game_start(Settings *settings, int opponent);
    3.42  
    3.43  #ifdef	__cplusplus
     4.1 --- a/src/input.c	Wed Mar 19 10:08:25 2014 +0100
     4.2 +++ b/src/input.c	Wed Mar 19 15:36:54 2014 +0100
     4.3 @@ -30,7 +30,15 @@
     4.4  #include "input.h"
     4.5  #include <ncurses.h>
     4.6  
     4.7 -int prompt_yesno() {
     4.8 +void init_colorpairs() {
     4.9 +    init_pair(COL_YB, COLOR_YELLOW, COLOR_BLUE);
    4.10 +    init_pair(COL_BW, COLOR_BLACK, COLOR_WHITE);
    4.11 +    init_pair(COL_WB, COLOR_WHITE, COLOR_BLACK);
    4.12 +}
    4.13 +
    4.14 +int prompt_yesno(char *msg) {
    4.15 +    printw("%s (y/n)? ", msg);
    4.16 +    refresh();
    4.17      noecho();
    4.18      int ch;
    4.19      do {
     5.1 --- a/src/input.h	Wed Mar 19 10:08:25 2014 +0100
     5.2 +++ b/src/input.h	Wed Mar 19 15:36:54 2014 +0100
     5.3 @@ -34,7 +34,13 @@
     5.4  extern "C" {
     5.5  #endif
     5.6  
     5.7 -int prompt_yesno();
     5.8 +#define COL_YB 1
     5.9 +#define COL_BW 2
    5.10 +#define COL_WB 3
    5.11 +
    5.12 +void init_colorpairs();
    5.13 +
    5.14 +int prompt_yesno(char *msg);
    5.15  
    5.16  
    5.17  #ifdef	__cplusplus
     6.1 --- a/src/main.c	Wed Mar 19 10:08:25 2014 +0100
     6.2 +++ b/src/main.c	Wed Mar 19 15:36:54 2014 +0100
     6.3 @@ -28,9 +28,11 @@
     6.4   */
     6.5  
     6.6  #include "terminal-chess.h"
     6.7 +#include "game.h"
     6.8 +#include "input.h"
     6.9  #include <string.h>
    6.10  #include <time.h>
    6.11 -#include <ncurses.h>
    6.12 +#include <getopt.h>
    6.13  
    6.14  int get_settings(int argc, char **argv, Settings *settings) {
    6.15      char *valid;
    6.16 @@ -44,7 +46,7 @@
    6.17              settings->gameinfo.servercolor = BLACK;
    6.18              break;
    6.19          case 'r':
    6.20 -            settings->gameinfo.servercolor = (rand()>>5) & 1 ? WHITE : BLACK;
    6.21 +            settings->gameinfo.servercolor = rand() & 1 ? WHITE : BLACK;
    6.22              break;
    6.23          case 't':
    6.24          case 'a':
    6.25 @@ -125,11 +127,7 @@
    6.26      refresh();
    6.27  }
    6.28  
    6.29 -static WINDOW* window;
    6.30 -
    6.31  void leavescr() {
    6.32 -    mvprintw(getmaxy(window)-1, 0, "Leaving terminal-chess. Press any key...");
    6.33 -    getch();
    6.34      endwin();
    6.35  }
    6.36  
    6.37 @@ -162,9 +160,17 @@
    6.38          );
    6.39          return EXIT_SUCCESS;
    6.40      }
    6.41 -    
    6.42 -    window = initscr();
    6.43 +    tchess_window = initscr();
    6.44      cbreak();
    6.45 +    if (has_colors()) {
    6.46 +        start_color();
    6.47 +        init_colorpairs();
    6.48 +        bkgd(COLOR_PAIR(COL_YB));
    6.49 +    } else {
    6.50 +        fprintf(stderr, "Non-colored terminals are not supported yet.");
    6.51 +        endwin();
    6.52 +        return EXIT_FAILURE;
    6.53 +    }
    6.54      atexit(leavescr);
    6.55      
    6.56      return is_server(&settings) ? server_run(&settings) : client_run(&settings);
     7.1 --- a/src/network.c	Wed Mar 19 10:08:25 2014 +0100
     7.2 +++ b/src/network.c	Wed Mar 19 15:36:54 2014 +0100
     7.3 @@ -122,7 +122,7 @@
     7.4      send(socket, data, len, 0);
     7.5  }
     7.6  
     7.7 -int net_recieve_code(int socket) {
     7.8 +uint32_t net_recieve_code(int socket) {
     7.9      uint32_t code;
    7.10      recv(socket, &code, sizeof(uint32_t), 0);
    7.11      return ntohl(code);
     8.1 --- a/src/network.h	Wed Mar 19 10:08:25 2014 +0100
     8.2 +++ b/src/network.h	Wed Mar 19 15:36:54 2014 +0100
     8.3 @@ -40,8 +40,11 @@
     8.4  #define NETCODE_ACCEPT 0x00
     8.5  #define NETCODE_DECLINE 0x01
     8.6  #define NETCODE_GAMEINFO 0x10
     8.7 +#define NETCODE_MOVE 0x20
     8.8 +#define NETCODE_SURRENDER 0x21
     8.9 +#define NETCODE_REMIS 0x22
    8.10      
    8.11 -#define NETCODE_VERSION 1
    8.12 +#define NETCODE_VERSION 3
    8.13  
    8.14  typedef struct {
    8.15      int fd; /* -1, if we are the client */
    8.16 @@ -64,7 +67,7 @@
    8.17  
    8.18  void net_send_code(int socket, uint32_t code);
    8.19  void net_send_data(int socket, void *data, size_t len);
    8.20 -int net_recieve_code(int socket);
    8.21 +uint32_t net_recieve_code(int socket);
    8.22  void net_recieve_data(int socket, void *data, size_t len);
    8.23  
    8.24  
     9.1 --- a/src/terminal-chess.h	Wed Mar 19 10:08:25 2014 +0100
     9.2 +++ b/src/terminal-chess.h	Wed Mar 19 15:36:54 2014 +0100
     9.3 @@ -29,7 +29,7 @@
     9.4  
     9.5  #include <stdlib.h>
     9.6  #include <stdio.h>
     9.7 -#include <getopt.h>
     9.8 +#include <ncurses.h>
     9.9  #include "network.h"
    9.10  
    9.11  #ifndef TERMINAL_CHESS_H
    9.12 @@ -38,9 +38,9 @@
    9.13  #ifdef	__cplusplus
    9.14  extern "C" {
    9.15  #endif
    9.16 -    
    9.17 -#define WHITE 0
    9.18 -#define BLACK 1
    9.19 +
    9.20 +WINDOW* tchess_window;
    9.21 +
    9.22  #define TIME_MAX UINT16_MAX
    9.23      
    9.24  typedef struct {

mercurial