universe@6: /* universe@6: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@6: * universe@6: * Copyright 2014 Mike Becker. All rights reserved. universe@6: * universe@6: * Redistribution and use in source and binary forms, with or without universe@6: * modification, are permitted provided that the following conditions are met: universe@6: * universe@6: * 1. Redistributions of source code must retain the above copyright universe@6: * notice, this list of conditions and the following disclaimer. universe@6: * universe@6: * 2. Redistributions in binary form must reproduce the above copyright universe@6: * notice, this list of conditions and the following disclaimer in the universe@6: * documentation and/or other materials provided with the distribution. universe@6: * universe@6: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@6: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@6: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@6: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@6: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@6: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@6: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@6: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@6: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@6: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@6: * POSSIBILITY OF SUCH DAMAGE. universe@6: * universe@6: */ universe@6: universe@6: #include "game.h" universe@7: #include "input.h" universe@7: #include universe@7: #include universe@7: universe@7: static const uint8_t boardx = 10, boardy = 10; universe@7: universe@8: static void draw_board(Board board, uint8_t mycolor) { universe@7: universe@7: for (uint8_t y = 0 ; y < 8 ; y++) { universe@7: for (uint8_t x = 0 ; x < 8 ; x++) { universe@7: uint8_t col = board[y][x] & COLOR_MASK; universe@7: uint8_t piece = board[y][x] & PIECE_MASK; universe@7: char piecec = ' '; universe@7: switch (piece) { universe@7: case PAWN: piecec = 'P'; break; universe@7: case ROOK: piecec = 'R'; break; universe@7: case KNIGHT: piecec = 'N'; break; universe@7: case BISHOP: piecec = 'B'; break; universe@7: case QUEEN: piecec = 'Q'; break; universe@7: case KING: piecec = 'K'; break; universe@7: } universe@7: universe@7: attrset((col == WHITE ? A_BOLD : A_DIM) | universe@7: COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW)); universe@7: universe@8: int cy = mycolor == WHITE ? boardy-y : boardy-7+y; universe@8: int cx = mycolor == WHITE ? boardx+x*3 : boardx+21-x*3; universe@8: mvaddch(cy, cx, ' '); universe@8: mvaddch(cy, cx+1, piecec); universe@8: mvaddch(cy, cx+2, ' '); universe@7: } universe@7: } universe@7: universe@7: attrset(A_NORMAL); universe@7: for (uint8_t i = 0 ; i < 8 ; i++) { universe@8: int x = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3; universe@8: int y = mycolor == WHITE ? boardy-i : boardy-7+i; universe@8: mvaddch(boardy+1, x, 'a'+i); universe@8: mvaddch(y, boardx-2, '1'+i); universe@7: } universe@7: } universe@7: universe@8: static void apply_move(Board board, Move *move) { universe@8: board[move->fromrow][move->fromfile] = 0; universe@8: // TODO: care for en passant capture universe@8: board[move->torow][move->tofile] = move->piece; universe@8: } universe@8: universe@8: static _Bool validate_move(Board board, uint8_t mycolor, Move *move) { universe@8: _Bool result = TRUE; universe@8: universe@8: /* does piece exist */ universe@8: result &= board[move->fromrow][move->fromfile] == move->piece; universe@8: universe@8: /* is move rule conform */ universe@8: // TODO: make it so universe@8: universe@8: /* is piece blocked */ universe@8: // TODO: make it so universe@8: universe@8: /* is piece pinned */ universe@8: // TODO: make it so universe@8: universe@8: return result; universe@8: } universe@8: universe@8: static _Bool eval_move(Board board, uint8_t mycolor, char *movestr, Move *move) { universe@8: memset(move, 0, sizeof(Move)); universe@8: universe@8: size_t len = strlen(movestr); universe@8: universe@8: /* remove check */ universe@8: if (movestr[len-1] == '+') { universe@8: len--; movestr[len] = '\0'; universe@8: move->check = TRUE; universe@8: } universe@8: universe@8: if (len == 2) { universe@8: /* pawn move (e.g. "e4") */ universe@8: if (isfile(movestr[0]) && isrow(movestr[1])) { universe@8: move->piece = PAWN; universe@8: move->fromfile = move->tofile = fileidx(movestr[0]); universe@8: move->torow = rowidx(movestr[1]); universe@8: move->fromrow = rowidx(movestr[1]) + (mycolor == WHITE ? -1 : 1); universe@8: if (move->fromrow > 6) { universe@8: move->piece = 0; universe@8: } else { universe@8: /* advanced first move */ universe@8: if (move->fromrow == (mycolor == WHITE ? 2 : 5) && universe@8: board[move->fromrow][move->fromfile] != (mycolor|PAWN)) { universe@8: universe@8: move->fromrow += (mycolor == WHITE ? -1 : 1); universe@8: if (move->fromrow > 6) { universe@8: move->piece = 0; universe@8: } universe@8: } universe@8: } universe@8: } universe@8: } else if (len == 3) { universe@8: if (strcmp(movestr, "0-0") == 0) { universe@8: /* king side castling */ universe@8: move->piece = KING; universe@8: move->fromfile = fileidx('e'); universe@8: move->fromfile = fileidx('g'); universe@8: move->fromrow = move->torow = mycolor == WHITE ? 0 : 7; universe@8: } else { universe@8: /* unambiguous move (e.g. "Nf3") */ universe@8: } universe@8: universe@8: } else if (len == 4) { universe@8: /* ambiguous move (e.g. "Ndf3") */ universe@8: universe@8: /* unambiguous capture (e.g. "Nxf3", "dxe5") */ universe@8: universe@8: } else if (len == 5) { universe@8: /* queen side castling "O-O-O" */ universe@8: universe@8: /* ambiguous capture (e.g. "Ndxf3") */ universe@8: universe@8: /* long notation move (e.g. "Nc5a4") */ universe@8: universe@8: /* long notation capture (e.g. "e5xf6") */ universe@8: } else if (len == 6) { universe@8: /* long notation capture (e.g. "Nc5xf3") */ universe@8: } universe@8: universe@8: if (move->piece) { universe@8: move->piece |= mycolor; universe@8: return TRUE; universe@8: } else { universe@8: return FALSE; universe@8: } universe@8: } universe@8: universe@8: static int sendmove(Board board, uint8_t mycolor, int opponent) { universe@7: const size_t buflen = 8; universe@8: char movestr[buflen]; universe@7: _Bool remisrejected = FALSE; universe@7: universe@7: while (1) { universe@7: move(boardy+3, 0); universe@7: if (remisrejected) { universe@7: printw( universe@7: "Use chess notation to enter your move.\n" universe@7: "Remis offer rejected - type 'surr' to surrender. \n\n" universe@7: "Type your move: "); universe@7: } else { universe@7: printw( universe@7: "Use chess notation to enter your move.\n" universe@7: "Or type 'surr' to surrender or 'remis' to offer remis.\n\n" universe@7: "Type your move: "); universe@7: } universe@7: clrtoeol(); universe@7: refresh(); universe@8: getnstr(movestr, buflen); universe@7: universe@8: if (strncmp(movestr, "surr", buflen) == 0) { universe@7: printw("You surrendered!"); universe@8: refresh(); universe@7: net_send_code(opponent, NETCODE_SURRENDER); universe@7: return 1; universe@8: } else if (strncmp(movestr, "remis", buflen) == 0) { universe@7: if (!remisrejected) { universe@7: net_send_code(opponent, NETCODE_REMIS); universe@7: printw("Remis offer sent - waiting for acceptance..."); universe@7: refresh(); universe@7: if (net_recieve_code(opponent) == NETCODE_ACCEPT) { universe@7: printw("\rRemis accepted!"); universe@7: clrtoeol(); universe@8: refresh(); universe@7: return 1; universe@7: } else { universe@7: remisrejected = TRUE; universe@7: } universe@7: } universe@7: } else { universe@8: Move move; universe@8: if (eval_move(board, mycolor, movestr, &move)) { universe@8: net_send_code(opponent, NETCODE_MOVE); universe@8: net_send_data(opponent, &move, sizeof(Move)); universe@8: if (net_recieve_code(opponent) == NETCODE_ACCEPT) { universe@8: apply_move(board, &move); universe@8: return 0; universe@8: } else { universe@8: printw("Invalid move."); universe@8: clrtoeol(); universe@8: } universe@8: } else { universe@8: printw("Can't interpret move - please use algebraic notation."); universe@8: } universe@7: } universe@7: } universe@7: } universe@7: universe@8: static int recvmove(Board board, uint8_t mycolor, int opponent) { universe@7: universe@7: while (1) { universe@7: move(boardy+3, 0); universe@7: printw("Awaiting opponent move..."); universe@7: clrtoeol(); universe@7: refresh(); universe@7: universe@7: // TODO: nonblocking universe@7: uint32_t code = net_recieve_code(opponent); universe@8: universe@8: Move move; universe@7: switch (code) { universe@7: case NETCODE_SURRENDER: universe@7: printw("\rYour opponent surrendered!"); universe@7: clrtoeol(); universe@7: return 1; universe@7: case NETCODE_REMIS: universe@7: if (prompt_yesno( universe@7: "\rYour opponent offers remis - do you accept")) { universe@7: printw("\rRemis accepted!"); universe@7: clrtoeol(); universe@7: net_send_code(opponent, NETCODE_ACCEPT); universe@7: return 1; universe@7: } else { universe@7: net_send_code(opponent, NETCODE_DECLINE); universe@7: } universe@7: break; universe@7: case NETCODE_MOVE: universe@8: net_recieve_data(opponent, &move, sizeof(Move)); universe@8: if (validate_move(board, mycolor, &move)) { universe@8: apply_move(board, &move); universe@8: net_send_code(opponent, NETCODE_ACCEPT); universe@8: return 0; universe@8: } else { universe@8: net_send_code(opponent, NETCODE_DECLINE); universe@8: } universe@7: } universe@7: } universe@7: } universe@6: universe@6: void game_start(Settings *settings, int opponent) { universe@7: _Bool myturn = is_server(settings) == universe@7: (settings->gameinfo.servercolor == WHITE); universe@8: uint8_t mycolor = myturn ? WHITE:BLACK; universe@8: universe@7: _Bool running; universe@6: universe@7: Board board = { universe@7: {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK}, universe@7: {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN}, universe@7: {0, 0, 0, 0, 0, 0, 0, 0}, universe@7: {0, 0, 0, 0, 0, 0, 0, 0}, universe@7: {0, 0, 0, 0, 0, 0, 0, 0}, universe@7: {0, 0, 0, 0, 0, 0, 0, 0}, universe@7: {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN}, universe@7: {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK} universe@7: }; universe@7: universe@7: do { universe@7: clear(); universe@8: draw_board(board, mycolor); universe@7: if (myturn) { universe@8: running = !sendmove(board, mycolor, opponent); universe@7: } else { universe@8: running = !recvmove(board, mycolor, opponent); universe@7: flushinp(); // flush any input the user hacked in while waiting universe@7: } universe@7: myturn ^= 1; universe@7: } while (running); universe@7: universe@7: mvaddstr(getmaxy(tchess_window)-1, 0, universe@7: "Game has ended. Press any key to leave..."); universe@7: getch(); universe@6: }