src/game.c

Sat, 22 Mar 2014 16:25:49 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 22 Mar 2014 16:25:49 +0100
changeset 9
4e4f156bba58
parent 8
52d742aee695
child 10
1347e4dabac0
permissions
-rw-r--r--

implemented castling (without validation)

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2014 Mike Becker. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  *
    28  */
    30 #include "game.h"
    31 #include "input.h"
    32 #include <ncurses.h>
    33 #include <string.h>
    35 static const uint8_t boardx = 10, boardy = 10;
    37 static void draw_board(Board board, uint8_t mycolor) {
    39     for (uint8_t y = 0 ; y < 8 ; y++) {
    40         for (uint8_t x = 0 ; x < 8 ; x++) {
    41             uint8_t col = board[y][x] & COLOR_MASK;
    42             uint8_t piece = board[y][x] & PIECE_MASK;
    43             char piecec = ' ';
    44             switch (piece) {
    45                 case PAWN: piecec = 'P'; break;
    46                 case ROOK: piecec = 'R'; break;
    47                 case KNIGHT: piecec = 'N'; break;
    48                 case BISHOP: piecec = 'B'; break;
    49                 case QUEEN: piecec = 'Q'; break;
    50                 case KING: piecec = 'K'; break;
    51             }
    53             attrset((col == WHITE ? A_BOLD : A_DIM) |
    54                 COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
    56             int cy = mycolor == WHITE ? boardy-y : boardy-7+y;
    57             int cx = mycolor == WHITE ? boardx+x*3 : boardx+21-x*3;
    58             mvaddch(cy, cx, ' ');
    59             mvaddch(cy, cx+1, piecec);
    60             mvaddch(cy, cx+2, ' ');
    61         }
    62     }
    64     attrset(A_NORMAL);
    65     for (uint8_t i = 0 ; i < 8 ; i++) {
    66         int x = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3;
    67         int y = mycolor == WHITE ? boardy-i : boardy-7+i;
    68         mvaddch(boardy+1, x, 'a'+i);
    69         mvaddch(y, boardx-2, '1'+i);
    70     }
    71 }
    73 static void apply_move(Board board, Move *move) {
    74     board[move->fromrow][move->fromfile] = 0;
    75     // TODO: care for en passant capture
    76     board[move->torow][move->tofile] = move->piece;
    78     /* castling */
    79     if ((move->piece & PIECE_MASK) == KING &&
    80         move->fromfile == fileidx('e')) {
    81         uint8_t color = move->piece & COLOR_MASK;
    83         if (move->tofile == fileidx('g')) {
    84             board[move->torow][fileidx('h')] = 0;
    85             board[move->torow][fileidx('f')] = color|ROOK;
    86         } else if (move->tofile == fileidx('c')) {
    87             board[move->torow][fileidx('a')] = 0;
    88             board[move->torow][fileidx('d')] = color|ROOK;
    89         }
    90     }
    91 }
    93 static _Bool validate_move(Board board, uint8_t mycolor, Move *move) {
    94     _Bool result = TRUE;
    96     /* does piece exist */
    97     result &= board[move->fromrow][move->fromfile] == move->piece;
    99     /* does move comply to rules */
   100     // TODO: make it so
   102     /* is piece blocked */
   103     // TODO: make it so
   105     /* is piece pinned */
   106     // TODO: make it so
   108     return result;
   109 }
   111 static _Bool eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
   112     memset(move, 0, sizeof(Move));
   114     size_t len = strlen(mstr);
   116     /* remove check */
   117     if (mstr[len-1] == '+') {
   118         len--; mstr[len] = '\0';
   119         move->check = TRUE;
   120     }
   122     if (len == 2) {
   123         /* pawn move (e.g. "e4") */
   124         if (isfile(mstr[0]) && isrow(mstr[1])) {
   125             move->piece = PAWN;
   126             move->fromfile = move->tofile = fileidx(mstr[0]);
   127             move->torow = rowidx(mstr[1]);
   128             move->fromrow = rowidx(mstr[1]) + (mycolor == WHITE ? -1 : 1);
   129             if (move->fromrow > 6) {
   130                 move->piece = 0;
   131             } else {
   132                 /* advanced first move */
   133                 if (move->fromrow == (mycolor == WHITE ? 2 : 5) &&
   134                     board[move->fromrow][move->fromfile] != (mycolor|PAWN)) {
   136                     move->fromrow += (mycolor == WHITE ? -1 : 1);
   137                     if (move->fromrow > 6) {
   138                         move->piece = 0;
   139                     }
   140                 }
   141             }
   142         }
   143     } else if (len == 3) {
   144         if (strcmp(mstr, "O-O") == 0) {
   145             /* king side castling */
   146             move->piece = KING;
   147             move->fromfile = fileidx('e');
   148             move->tofile = fileidx('g');
   149             move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
   150         } else {
   151             /* unambiguous move (e.g. "Nf3") */
   152         }
   154     } else if (len == 4) {
   155         /* ambiguous move (e.g. "Ndf3") */
   157         /* unambiguous capture (e.g. "Nxf3", "dxe5") */
   159     } else if (len == 5) {
   160         if (strcmp(mstr, "O-O-O") == 0) {
   161             /* queen side castling "O-O-O" */
   162             move->piece = KING;
   163             move->fromfile = fileidx('e');
   164             move->tofile = fileidx('c');
   165             move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
   166         } else {
   167             /* ambiguous capture (e.g. "Ndxf3") */
   169             /* long notation move (e.g. "Nc5a4") */
   171             /* long notation capture (e.g. "e5xf6") */
   172         }
   173     } else if (len == 6) {
   174         /* long notation capture (e.g. "Nc5xf3") */
   175     }
   177     if (move->piece) {
   178         move->piece |= mycolor;
   179         return TRUE;
   180     } else {
   181         return FALSE;
   182     }
   183 }
   185 static int sendmove(Board board, uint8_t mycolor, int opponent) {
   186     const size_t buflen = 8;
   187     char movestr[buflen];
   188     _Bool remisrejected = FALSE;
   190     while (1) {
   191         move(boardy+3, 0);
   192         if (remisrejected) {
   193             printw(
   194                 "Use chess notation to enter your move.\n"
   195                 "Remis offer rejected - type 'surr' to surrender.      \n\n"
   196                 "Type your move: ");
   197         } else {
   198             printw(
   199                 "Use chess notation to enter your move.\n"
   200                 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
   201                 "Type your move: ");
   202         }
   203         clrtoeol();
   204         refresh();
   205         getnstr(movestr, buflen);
   207         if (strncmp(movestr, "surr", buflen) == 0) {
   208             printw("You surrendered!");
   209             refresh();
   210             net_send_code(opponent, NETCODE_SURRENDER);
   211             return 1;
   212         } else if (strncmp(movestr, "remis", buflen) == 0) {
   213             if (!remisrejected) {
   214                 net_send_code(opponent, NETCODE_REMIS);
   215                 printw("Remis offer sent - waiting for acceptance...");
   216                 refresh();
   217                 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
   218                     printw("\rRemis accepted!");
   219                     clrtoeol();
   220                     refresh();
   221                     return 1;
   222                 } else {
   223                     remisrejected = TRUE;
   224                 }
   225             }
   226         } else {
   227             Move move;
   228             if (eval_move(board, mycolor, movestr, &move)) {
   229                 net_send_code(opponent, NETCODE_MOVE);
   230                 net_send_data(opponent, &move, sizeof(Move));
   231                 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
   232                     apply_move(board, &move);
   233                     return 0;
   234                 } else {
   235                     printw("Invalid move.");
   236                     clrtoeol();
   237                 }
   238             } else {
   239                 printw("Can't interpret move - please use algebraic notation.");
   240             }
   241         }
   242     }
   243 }
   245 static int recvmove(Board board, uint8_t mycolor, int opponent) {
   247     while (1) {
   248         move(boardy+3, 0);
   249         printw("Awaiting opponent move...");
   250         clrtoeol();
   251         refresh();
   253         // TODO: nonblocking
   254         uint32_t code = net_recieve_code(opponent);
   256         Move move;
   257         switch (code) {
   258             case NETCODE_SURRENDER:
   259                 printw("\rYour opponent surrendered!");
   260                 clrtoeol();
   261                 return 1;
   262             case NETCODE_REMIS:
   263                 if (prompt_yesno(
   264                     "\rYour opponent offers remis - do you accept")) {
   265                     printw("\rRemis accepted!");
   266                     clrtoeol();
   267                     net_send_code(opponent, NETCODE_ACCEPT);
   268                     return 1;
   269                 } else {
   270                     net_send_code(opponent, NETCODE_DECLINE);
   271                 }
   272                 break;
   273             case NETCODE_MOVE:
   274                 net_recieve_data(opponent, &move, sizeof(Move));
   275                 if (validate_move(board, mycolor, &move)) {
   276                     apply_move(board, &move);
   277                     net_send_code(opponent, NETCODE_ACCEPT);
   278                     return 0;
   279                 } else {
   280                     net_send_code(opponent, NETCODE_DECLINE);
   281                 }
   282         }
   283     }
   284 }
   286 void game_start(Settings *settings, int opponent) {
   287     _Bool myturn = is_server(settings) ==
   288         (settings->gameinfo.servercolor == WHITE);
   289     uint8_t mycolor = myturn ? WHITE:BLACK;
   291     _Bool running;
   293     Board board = {
   294         {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
   295         {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
   296         {0,     0,       0,       0,      0,     0,       0,       0},
   297         {0,     0,       0,       0,      0,     0,       0,       0},
   298         {0,     0,       0,       0,      0,     0,       0,       0},
   299         {0,     0,       0,       0,      0,     0,       0,       0},
   300         {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
   301         {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
   302     };
   304     do {
   305         clear();
   306         draw_board(board, mycolor);
   307         if (myturn) {
   308             running = !sendmove(board, mycolor, opponent);
   309         } else {
   310             running = !recvmove(board, mycolor, opponent);
   311             flushinp(); // flush any input the user hacked in while waiting
   312         }
   313         myturn ^= 1;
   314     }  while (running);
   316     mvaddstr(getmaxy(tchess_window)-1, 0,
   317         "Game has ended. Press any key to leave...");
   318     getch();
   319 }

mercurial