Mon, 31 Mar 2014 11:41:08 +0200
added optional alternate config for chess lib
/* * 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(Board board, MoveListRoot *movelist, uint8_t mycolor) { 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; 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 = mycolor == WHITE ? boardy-y : boardy-7+y; int cx = 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 = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3; int y = 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 = movelist->first; while (logelem) { logi++; if (logi % 2 == 0) { if ((logi - 2) % 4 == 0) { logy++; wmove(tchess_window, 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(Board board, MoveListRoot *movelist, uint8_t mycolor, int opponent) { const size_t buflen = 8; char movestr[buflen]; _Bool remisrejected = FALSE; uint8_t code; int inputy = getmaxy(tchess_window) - 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(board, mycolor, movestr, &move); switch (eval_result) { case VALID_MOVE_SYNTAX: net_send_code(opponent, NETCODE_MOVE); net_send_data(opponent, &move, sizeof(Move)); code = net_recieve_code(opponent); move.check = code == NETCODE_CHECK; move.checkmate = code == NETCODE_CHECKMATE; addmove(movelist, &move); if (code == NETCODE_DECLINE) { printw("Invalid move."); } else { apply_move(board, &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(Board board, MoveListRoot *movelist, int opponent) { int inputy = getmaxy(tchess_window) - 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(board, &move)) { apply_move(board, &move); addmove(movelist, &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 freemovelist(MoveListRoot* list) { MoveList *elem; elem = list->first; while (elem) { MoveList *cur = elem; elem = elem->next; free(cur); }; free(list); } void addmove(MoveListRoot* list, Move *move) { MoveList *elem = malloc(sizeof(MoveList)); elem->next = NULL; elem->move = *move; if (list->last) { list->last->next = elem; list->last = elem; } else { list->first = list->last = elem; } } void game_start(Settings *settings, int opponent) { _Bool myturn = is_server(settings) == (settings->gameinfo.servercolor == WHITE); uint8_t mycolor = myturn ? WHITE:BLACK; _Bool running; MoveListRoot* movelist = calloc(1, sizeof(MoveListRoot)); 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, movelist, mycolor); if (myturn) { running = !sendmove(board, movelist, mycolor, opponent); } else { running = !recvmove(board, movelist, opponent); flushinp(); // flush any input the user hacked in while waiting } myturn ^= TRUE; } while (running); freemovelist(movelist); mvaddstr(getmaxy(tchess_window)-1, 0, "Game has ended. Press any key to leave..."); getch(); }