Tue, 01 Apr 2014 10:28:08 +0200
implemented queen
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2014 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "game.h" #include "network.h" #include "input.h" #include <ncurses.h> #include <string.h> static const uint8_t boardx = 10, boardy = 10; static void draw_board(GameState *gamestate) { for (uint8_t y = 0 ; y < 8 ; y++) { for (uint8_t x = 0 ; x < 8 ; x++) { uint8_t col = gamestate->board[y][x] & COLOR_MASK; uint8_t piece = gamestate->board[y][x] & PIECE_MASK; char piecec; if (piece) { piecec = piece == PAWN ? 'P' : getpiecechr(piece); } else { piecec = ' '; } attrset((col == WHITE ? A_BOLD : A_DIM) | COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW)); int cy = gamestate->mycolor == WHITE ? boardy-y : boardy-7+y; int cx = gamestate->mycolor == WHITE ? boardx+x*3 : boardx+21-x*3; mvaddch(cy, cx, ' '); mvaddch(cy, cx+1, piecec); mvaddch(cy, cx+2, ' '); } } attrset(A_NORMAL); for (uint8_t i = 0 ; i < 8 ; i++) { int x = gamestate->mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3; int y = gamestate->mycolor == WHITE ? boardy-i : boardy-7+i; mvaddch(boardy+1, x, 'a'+i); mvaddch(y, boardx-2, '1'+i); } /* move log */ // TODO: introduce window to avoid bugs with a long move log uint8_t logy = 0; const uint8_t logx = boardx + 30; int logi = 1; MoveList *logelem = gamestate->movelist; while (logelem) { logi++; if (logi % 2 == 0) { if ((logi - 2) % 4 == 0) { logy++; move(logy, logx); } printw("%d. ", logi / 2); } if (logelem) { Move move = logelem->move; char logstr[] = { getpiecechr(move.piece), filechr(move.fromfile), rowchr(move.fromrow), move.capture ? 'x':'\0', filechr(move.tofile), rowchr(move.torow), move.check ? '+' : (move.checkmate ? '#' : (move.promotion ? '=' : '\0')), move.promotion ? getpiecechr(move.promotion) : '\0', ' ' }; for (int stri = 0 ; stri < sizeof(logstr) ; stri++) { if (logstr[stri]) { addch(logstr[stri]); } } logelem = logelem->next; } } } static int sendmove(GameState *gamestate, int opponent) { const size_t buflen = 8; char movestr[buflen]; _Bool remisrejected = FALSE; uint8_t code; int inputy = getmaxy(stdscr) - 6; while (1) { move(inputy, 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(movestr, buflen); if (strncmp(movestr, "surr", buflen) == 0) { printw("You surrendered!"); clrtoeol(); refresh(); net_send_code(opponent, NETCODE_SURRENDER); return 1; } else if (strncmp(movestr, "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(); refresh(); return 1; } else { remisrejected = TRUE; } } } else { Move move; int eval_result = eval_move(gamestate, movestr, &move); switch (eval_result) { case VALID_MOVE_SYNTAX: net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); code = net_recieve_code(opponent); move.check = code == NETCODE_CHECK; move.checkmate = code == NETCODE_CHECKMATE; if (code == NETCODE_DECLINE) { printw("Invalid move."); } else { apply_move(gamestate, &move); if (move.checkmate) { printw("Checkmate!"); clrtoeol(); return 1; } else { return 0; } } break; case AMBIGUOUS_MOVE: printw("Ambiguous move - please specify the piece to move."); break; case INVALID_POSITION: printw("Cannot find the piece that shall be moved."); break; case NEED_PROMOTION: printw("You need to promote the pawn (append \"=Q\" e.g.)!"); break; default: printw("Can't interpret move - please use algebraic notation."); } clrtoeol(); } } } static int recvmove(GameState *gamestate, int opponent) { int inputy = getmaxy(stdscr) - 6; while (1) { move(inputy, 0); printw("Awaiting opponent move..."); clrtoeol(); refresh(); // TODO: nonblocking uint32_t code = net_recieve_code(opponent); Move move; 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: net_recieve_data(opponent, &move, sizeof(Move)); if (validate_move(gamestate, &move)) { apply_move(gamestate, &move); if (move.check) { net_send_code(opponent, NETCODE_CHECK); } else if (move.checkmate) { net_send_code(opponent, NETCODE_CHECKMATE); } else { net_send_code(opponent, NETCODE_ACCEPT); } return 0; } else { net_send_code(opponent, NETCODE_DECLINE); } } } } void game_start(Settings *settings, int opponent) { _Bool myturn = is_server(settings) == (settings->gameinfo.servercolor == WHITE); GameState gamestate; Board initboard = { {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} }; memcpy(gamestate.board, initboard, sizeof(Board)); gamestate.mycolor = myturn ? WHITE:BLACK; gamestate.movelist = gamestate.lastmove = NULL; _Bool running; do { clear(); draw_board(&gamestate); if (myturn) { running = !sendmove(&gamestate, opponent); } else { running = !recvmove(&gamestate, opponent); flushinp(); // flush any input the user hacked in while waiting } myturn ^= TRUE; } while (running); gamestate_cleanup(&gamestate); mvaddstr(getmaxy(stdscr)-1, 0, "Game has ended. Press any key to leave..."); getch(); }