Wed, 19 Mar 2014 15:36:54 +0100
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 {