src/game.c

Sat, 29 Mar 2014 16:53:58 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 29 Mar 2014 16:53:58 +0100
changeset 18
6008840b859e
parent 17
2aed5418e142
child 19
6a26114297a1
permissions
-rw-r--r--

fixed bishop + added pawn promotion + added move log

universe@6 1 /*
universe@6 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@6 3 *
universe@6 4 * Copyright 2014 Mike Becker. All rights reserved.
universe@6 5 *
universe@6 6 * Redistribution and use in source and binary forms, with or without
universe@6 7 * modification, are permitted provided that the following conditions are met:
universe@6 8 *
universe@6 9 * 1. Redistributions of source code must retain the above copyright
universe@6 10 * notice, this list of conditions and the following disclaimer.
universe@6 11 *
universe@6 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@6 13 * notice, this list of conditions and the following disclaimer in the
universe@6 14 * documentation and/or other materials provided with the distribution.
universe@6 15 *
universe@6 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@6 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@6 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@6 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@6 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@6 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@6 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@6 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@6 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@6 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@6 26 * POSSIBILITY OF SUCH DAMAGE.
universe@6 27 *
universe@6 28 */
universe@6 29
universe@6 30 #include "game.h"
universe@7 31 #include "input.h"
universe@10 32 #include "rules/rules.h"
universe@7 33 #include <ncurses.h>
universe@7 34 #include <string.h>
universe@7 35
universe@7 36 static const uint8_t boardx = 10, boardy = 10;
universe@7 37
universe@18 38 static uint8_t getpiecechr(uint8_t piece) {
universe@18 39 switch (piece & PIECE_MASK) {
universe@18 40 case ROOK: return 'R';
universe@18 41 case KNIGHT: return 'N';
universe@18 42 case BISHOP: return 'B';
universe@18 43 case QUEEN: return 'Q';
universe@18 44 case KING: return 'K';
universe@18 45 default: return '\0';
universe@18 46 }
universe@18 47 }
universe@18 48
universe@18 49 /**
universe@18 50 * Maps a character to a piece.
universe@18 51 *
universe@18 52 * Does not work for pawns, since they don't have a character.
universe@18 53 *
universe@18 54 * @param c one of R,N,B,Q,K
universe@18 55 * @return numeric value for the specified piece
universe@18 56 */
universe@18 57 static uint8_t getpiece(char c) {
universe@18 58 switch (c) {
universe@18 59 case 'R': return ROOK;
universe@18 60 case 'N': return KNIGHT;
universe@18 61 case 'B': return BISHOP;
universe@18 62 case 'Q': return QUEEN;
universe@18 63 case 'K': return KING;
universe@18 64 default: return 0;
universe@18 65 }
universe@18 66 }
universe@18 67
universe@18 68 /**
universe@18 69 * Guesses the location of a piece for short algebraic notation.
universe@18 70 *
universe@18 71 * @param board the current state of the board
universe@18 72 * @param move the move date to operate on
universe@18 73 * @return status code (see rules/rules.h for the codes)
universe@18 74 */
universe@18 75 static int getlocation(Board board, Move *move) {
universe@18 76 uint8_t piece = move->piece & PIECE_MASK;
universe@18 77 switch (piece) {
universe@18 78 case PAWN: return pawn_getlocation(board, move);
universe@18 79 case ROOK: return rook_getlocation(board, move);
universe@18 80 case KNIGHT: return knight_getlocation(board, move);
universe@18 81 case BISHOP: return bishop_getlocation(board, move);
universe@18 82 case QUEEN: return queen_getlocation(board, move);
universe@18 83 case KING: return king_getlocation(board, move);
universe@18 84 default: return INVALID_MOVE_SYNTAX;
universe@18 85 }
universe@18 86 }
universe@18 87
universe@18 88
universe@18 89 static void draw_board(Board board, MoveListRoot *movelist, uint8_t mycolor) {
universe@7 90
universe@7 91 for (uint8_t y = 0 ; y < 8 ; y++) {
universe@7 92 for (uint8_t x = 0 ; x < 8 ; x++) {
universe@7 93 uint8_t col = board[y][x] & COLOR_MASK;
universe@7 94 uint8_t piece = board[y][x] & PIECE_MASK;
universe@18 95 char piecec;
universe@18 96 if (piece) {
universe@18 97 piecec = piece == PAWN ? 'P' : getpiecechr(piece);
universe@18 98 } else {
universe@18 99 piecec = ' ';
universe@7 100 }
universe@7 101
universe@7 102 attrset((col == WHITE ? A_BOLD : A_DIM) |
universe@7 103 COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
universe@7 104
universe@8 105 int cy = mycolor == WHITE ? boardy-y : boardy-7+y;
universe@8 106 int cx = mycolor == WHITE ? boardx+x*3 : boardx+21-x*3;
universe@8 107 mvaddch(cy, cx, ' ');
universe@8 108 mvaddch(cy, cx+1, piecec);
universe@8 109 mvaddch(cy, cx+2, ' ');
universe@7 110 }
universe@7 111 }
universe@7 112
universe@7 113 attrset(A_NORMAL);
universe@7 114 for (uint8_t i = 0 ; i < 8 ; i++) {
universe@8 115 int x = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3;
universe@8 116 int y = mycolor == WHITE ? boardy-i : boardy-7+i;
universe@8 117 mvaddch(boardy+1, x, 'a'+i);
universe@8 118 mvaddch(y, boardx-2, '1'+i);
universe@7 119 }
universe@18 120
universe@18 121 /* move log */
universe@18 122 // TODO: introduce window to avoid bugs with a long move log
universe@18 123 uint8_t logy = 0;
universe@18 124 const uint8_t logx = boardx + 30;
universe@18 125 int logi = 1;
universe@18 126 MoveList *logelem = movelist->first;
universe@18 127
universe@18 128 while (logelem) {
universe@18 129 logi++;
universe@18 130 if (logi % 2 == 0) {
universe@18 131 if ((logi - 2) % 4 == 0) {
universe@18 132 logy++;
universe@18 133 wmove(tchess_window, logy, logx);
universe@18 134 }
universe@18 135 printw("%d. ", logi / 2);
universe@18 136 }
universe@18 137
universe@18 138 if (logelem) {
universe@18 139 Move move = logelem->move;
universe@18 140 char logstr[] = {
universe@18 141 getpiecechr(move.piece),
universe@18 142 filechr(move.fromfile), rowchr(move.fromrow),
universe@18 143 move.capture ? 'x':'\0',
universe@18 144 filechr(move.tofile), rowchr(move.torow),
universe@18 145 move.check ? '+' : (move.checkmate ? '#' :
universe@18 146 (move.promotion ? '=' : '\0')),
universe@18 147 move.promotion ? getpiecechr(move.promotion) : '\0',
universe@18 148 ' '
universe@18 149 };
universe@18 150 for (int stri = 0 ; stri < sizeof(logstr) ; stri++) {
universe@18 151 if (logstr[stri]) {
universe@18 152 addch(logstr[stri]);
universe@18 153 }
universe@18 154 }
universe@18 155
universe@18 156 logelem = logelem->next;
universe@18 157 }
universe@18 158 }
universe@7 159 }
universe@7 160
universe@13 161 /**
universe@13 162 * Applies a move and deletes captured pieces.
universe@13 163 *
universe@13 164 * @param board the current board state
universe@13 165 * @param move the move to apply
universe@13 166 */
universe@8 167 static void apply_move(Board board, Move *move) {
universe@15 168 uint8_t piece = move->piece & PIECE_MASK;
universe@15 169 uint8_t color = move->piece & COLOR_MASK;
universe@15 170
universe@15 171 /* en passant capture */
universe@15 172 if (move->capture && piece == PAWN &&
universe@15 173 mdst(board, move) == 0) {
universe@15 174 board[move->fromrow][move->tofile] = 0;
universe@15 175 }
universe@15 176
universe@15 177 /* remove old en passant threats */
universe@15 178 for (uint8_t file = 0 ; file < 8 ; file++) {
universe@15 179 board[3][file] &= ~ENPASSANT_THREAT;
universe@15 180 board[4][file] &= ~ENPASSANT_THREAT;
universe@15 181 }
universe@15 182
universe@15 183 /* add new en passant threat */
universe@15 184 if (piece == PAWN && (
universe@15 185 (move->fromrow == 1 && move->torow == 3) ||
universe@15 186 (move->fromrow == 6 && move->torow == 4))) {
universe@15 187 move->piece |= ENPASSANT_THREAT;
universe@15 188 }
universe@15 189
universe@18 190 /* move (and maybe capture or promote) */
universe@14 191 msrc(board, move) = 0;
universe@18 192 if (move->promotion) {
universe@18 193 mdst(board, move) = move->promotion;
universe@18 194 } else {
universe@18 195 mdst(board, move) = move->piece;
universe@18 196 }
universe@9 197
universe@9 198 /* castling */
universe@15 199 if (piece == KING &&
universe@9 200 move->fromfile == fileidx('e')) {
universe@9 201
universe@9 202 if (move->tofile == fileidx('g')) {
universe@9 203 board[move->torow][fileidx('h')] = 0;
universe@9 204 board[move->torow][fileidx('f')] = color|ROOK;
universe@9 205 } else if (move->tofile == fileidx('c')) {
universe@9 206 board[move->torow][fileidx('a')] = 0;
universe@9 207 board[move->torow][fileidx('d')] = color|ROOK;
universe@9 208 }
universe@9 209 }
universe@8 210 }
universe@8 211
universe@13 212 /**
universe@13 213 * Validates move by applying chess rules.
universe@13 214 * @param board the current board state
universe@13 215 * @param move the move to validate
universe@13 216 * @return TRUE, if the move complies to chess rules, FALSE otherwise
universe@13 217 */
universe@11 218 static _Bool validate_move(Board board, Move *move) {
universe@10 219 _Bool result;
universe@8 220
universe@13 221 /* validate indices (don't trust opponent) */
universe@13 222 if (!chkidx(move)) {
universe@13 223 return FALSE;
universe@13 224 }
universe@13 225
universe@8 226 /* does piece exist */
universe@14 227 result = msrc(board, move) == move->piece;
universe@8 228
universe@14 229 /* can't capture own pieces */
universe@14 230 if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) {
universe@14 231 return FALSE;
universe@14 232 }
universe@14 233
universe@14 234 /* validate individual rules */
universe@10 235 switch (move->piece & PIECE_MASK) {
universe@10 236 case PAWN:
universe@10 237 result = result && pawn_chkrules(board, move);
universe@10 238 result = result && !pawn_isblocked(board, move);
universe@10 239 break;
universe@10 240 case ROOK:
universe@16 241 result = result && rook_chkrules(move);
universe@10 242 result = result && !rook_isblocked(board, move);
universe@10 243 break;
universe@10 244 case KNIGHT:
universe@16 245 result = result && knight_chkrules(move);
universe@10 246 result = result && !knight_isblocked(board, move);
universe@10 247 break;
universe@10 248 case BISHOP:
universe@16 249 result = result && bishop_chkrules(move);
universe@10 250 result = result && !bishop_isblocked(board, move);
universe@10 251 break;
universe@10 252 case QUEEN:
universe@16 253 result = result && queen_chkrules(move);
universe@10 254 result = result && !queen_isblocked(board, move);
universe@10 255 break;
universe@10 256 case KING:
universe@10 257 result = result && king_chkrules(board, move);
universe@10 258 result = result && !king_isblocked(board, move);
universe@10 259 break;
universe@10 260 default:
universe@10 261 result = FALSE;
universe@10 262 }
universe@8 263
universe@8 264 /* is piece pinned */
universe@8 265 // TODO: make it so
universe@8 266
universe@11 267 /* correct check and checkmate flags */
universe@11 268 // TODO: make it so
universe@11 269
universe@8 270 return result;
universe@8 271 }
universe@8 272
universe@12 273 /**
universe@12 274 * Evaluates a move syntactically and stores the move data in the specified
universe@12 275 * object.
universe@12 276 *
universe@12 277 * @param board the current state of the board
universe@12 278 * @param mycolor the color of the current player
universe@12 279 * @param mstr the input string to parse
universe@12 280 * @param move a pointer to object where the move data shall be stored
universe@16 281 * @return status code (see rules/rules.h for the list of codes)
universe@12 282 */
universe@16 283 static int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
universe@8 284 memset(move, 0, sizeof(Move));
universe@12 285 move->fromfile = POS_UNSPECIFIED;
universe@12 286 move->fromrow = POS_UNSPECIFIED;
universe@18 287
universe@9 288 size_t len = strlen(mstr);
universe@8 289
universe@11 290 /* evaluate check/checkmate flags */
universe@9 291 if (mstr[len-1] == '+') {
universe@9 292 len--; mstr[len] = '\0';
universe@8 293 move->check = TRUE;
universe@11 294 } else if (mstr[len-1] == '#') {
universe@11 295 len--; mstr[len] = '\0';
universe@11 296 move->checkmate = TRUE;
universe@8 297 }
universe@8 298
universe@18 299 /* evaluate promotion */
universe@18 300 if (len > 3 && mstr[len-2] == '=') {
universe@18 301 move->promotion = getpiece(mstr[len-1]);
universe@18 302 if (!move->promotion) {
universe@18 303 return INVALID_MOVE_SYNTAX;
universe@18 304 } else {
universe@18 305 move->promotion |= mycolor;
universe@18 306 len -= 2;
universe@18 307 mstr[len] = 0;
universe@18 308 }
universe@18 309 }
universe@18 310
universe@8 311 if (len == 2) {
universe@8 312 /* pawn move (e.g. "e4") */
universe@13 313 move->piece = PAWN;
universe@13 314 move->tofile = fileidx(mstr[0]);
universe@13 315 move->torow = rowidx(mstr[1]);
universe@8 316 } else if (len == 3) {
universe@9 317 if (strcmp(mstr, "O-O") == 0) {
universe@8 318 /* king side castling */
universe@12 319 move->piece = KING;
universe@8 320 move->fromfile = fileidx('e');
universe@9 321 move->tofile = fileidx('g');
universe@8 322 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
universe@8 323 } else {
universe@13 324 /* move (e.g. "Nf3") */
universe@12 325 move->piece = getpiece(mstr[0]);
universe@13 326 move->tofile = fileidx(mstr[1]);
universe@13 327 move->torow = rowidx(mstr[2]);
universe@8 328 }
universe@8 329
universe@8 330 } else if (len == 4) {
universe@13 331 move->piece = getpiece(mstr[0]);
universe@15 332 if (!move->piece) {
universe@15 333 move->piece = PAWN;
universe@15 334 move->fromfile = fileidx(mstr[0]);
universe@15 335 }
universe@13 336 if (mstr[1] == 'x') {
universe@13 337 /* capture (e.g. "Nxf3", "dxe5") */
universe@13 338 move->capture = TRUE;
universe@15 339 } else {
universe@15 340 /* move (e.g. "Ndf3", "N2c3", "e2e4") */
universe@15 341 if (isfile(mstr[1])) {
universe@15 342 move->fromfile = fileidx(mstr[1]);
universe@15 343 if (move->piece == PAWN) {
universe@15 344 move->piece = 0;
universe@15 345 }
universe@15 346 } else {
universe@15 347 move->fromrow = rowidx(mstr[1]);
universe@13 348 }
universe@13 349 }
universe@13 350 move->tofile = fileidx(mstr[2]);
universe@13 351 move->torow = rowidx(mstr[3]);
universe@8 352 } else if (len == 5) {
universe@9 353 if (strcmp(mstr, "O-O-O") == 0) {
universe@9 354 /* queen side castling "O-O-O" */
universe@12 355 move->piece = KING;
universe@9 356 move->fromfile = fileidx('e');
universe@9 357 move->tofile = fileidx('c');
universe@9 358 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
universe@9 359 } else {
universe@13 360 move->piece = getpiece(mstr[0]);
universe@13 361 if (mstr[2] == 'x') {
universe@13 362 move->capture = TRUE;
universe@13 363 if (move->piece) {
universe@13 364 /* capture (e.g. "Ndxf3") */
universe@13 365 move->fromfile = fileidx(mstr[1]);
universe@13 366 } else {
universe@13 367 /* long notation capture (e.g. "e5xf6") */
universe@13 368 move->piece = PAWN;
universe@13 369 move->fromfile = fileidx(mstr[0]);
universe@13 370 move->fromrow = rowidx(mstr[1]);
universe@13 371 }
universe@13 372 } else {
universe@13 373 /* long notation move (e.g. "Nc5a4") */
universe@13 374 move->fromfile = fileidx(mstr[1]);
universe@13 375 move->fromrow = rowidx(mstr[2]);
universe@13 376 }
universe@13 377 move->tofile = fileidx(mstr[3]);
universe@13 378 move->torow = rowidx(mstr[4]);
universe@9 379 }
universe@8 380 } else if (len == 6) {
universe@8 381 /* long notation capture (e.g. "Nc5xf3") */
universe@13 382 if (mstr[3] == 'x') {
universe@13 383 move->capture = TRUE;
universe@13 384 move->piece = getpiece(mstr[0]);
universe@13 385 move->fromfile = fileidx(mstr[1]);
universe@13 386 move->fromrow = rowidx(mstr[2]);
universe@13 387 move->tofile = fileidx(mstr[4]);
universe@13 388 move->torow = rowidx(mstr[5]);
universe@13 389 }
universe@8 390 }
universe@12 391
universe@13 392
universe@12 393 if (move->piece) {
universe@18 394 if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0)
universe@18 395 && !move->promotion) {
universe@18 396 return NEED_PROMOTION;
universe@18 397 }
universe@18 398
universe@12 399 move->piece |= mycolor;
universe@13 400 if (move->fromfile == POS_UNSPECIFIED
universe@13 401 || move->fromrow == POS_UNSPECIFIED) {
universe@16 402 return getlocation(board, move);
universe@13 403 } else {
universe@16 404 return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
universe@13 405 }
universe@13 406 } else {
universe@16 407 return INVALID_MOVE_SYNTAX;
universe@12 408 }
universe@8 409 }
universe@8 410
universe@18 411 static int sendmove(Board board, MoveListRoot *movelist,
universe@18 412 uint8_t mycolor, int opponent) {
universe@18 413
universe@7 414 const size_t buflen = 8;
universe@8 415 char movestr[buflen];
universe@7 416 _Bool remisrejected = FALSE;
universe@11 417 uint8_t code;
universe@7 418
universe@18 419 int inputy = getmaxy(tchess_window) - 6;
universe@7 420 while (1) {
universe@18 421 move(inputy, 0);
universe@7 422 if (remisrejected) {
universe@7 423 printw(
universe@7 424 "Use chess notation to enter your move.\n"
universe@7 425 "Remis offer rejected - type 'surr' to surrender. \n\n"
universe@7 426 "Type your move: ");
universe@7 427 } else {
universe@7 428 printw(
universe@7 429 "Use chess notation to enter your move.\n"
universe@7 430 "Or type 'surr' to surrender or 'remis' to offer remis.\n\n"
universe@7 431 "Type your move: ");
universe@7 432 }
universe@7 433 clrtoeol();
universe@7 434 refresh();
universe@8 435 getnstr(movestr, buflen);
universe@7 436
universe@8 437 if (strncmp(movestr, "surr", buflen) == 0) {
universe@7 438 printw("You surrendered!");
universe@16 439 clrtoeol();
universe@8 440 refresh();
universe@7 441 net_send_code(opponent, NETCODE_SURRENDER);
universe@7 442 return 1;
universe@8 443 } else if (strncmp(movestr, "remis", buflen) == 0) {
universe@7 444 if (!remisrejected) {
universe@7 445 net_send_code(opponent, NETCODE_REMIS);
universe@7 446 printw("Remis offer sent - waiting for acceptance...");
universe@7 447 refresh();
universe@7 448 if (net_recieve_code(opponent) == NETCODE_ACCEPT) {
universe@7 449 printw("\rRemis accepted!");
universe@7 450 clrtoeol();
universe@8 451 refresh();
universe@7 452 return 1;
universe@7 453 } else {
universe@7 454 remisrejected = TRUE;
universe@7 455 }
universe@7 456 }
universe@7 457 } else {
universe@8 458 Move move;
universe@16 459 int eval_result = eval_move(board, mycolor, movestr, &move);
universe@16 460 switch (eval_result) {
universe@18 461 case VALID_MOVE_SYNTAX:
universe@18 462 net_send_code(opponent, NETCODE_MOVE);
universe@18 463 net_send_data(opponent, &move, sizeof(Move));
universe@18 464 code = net_recieve_code(opponent);
universe@18 465 move.check = code == NETCODE_CHECK;
universe@18 466 move.checkmate = code == NETCODE_CHECKMATE;
universe@18 467 addmove(movelist, &move);
universe@18 468 if (code == NETCODE_DECLINE) {
universe@18 469 printw("Invalid move.");
universe@18 470 } else {
universe@18 471 apply_move(board, &move);
universe@18 472 if (move.checkmate) {
universe@18 473 printw("Checkmate!");
universe@18 474 clrtoeol();
universe@18 475 return 1;
universe@14 476 } else {
universe@18 477 return 0;
universe@11 478 }
universe@18 479 }
universe@18 480 break;
universe@18 481 case AMBIGUOUS_MOVE:
universe@18 482 printw("Ambiguous move - please specify the piece to move.");
universe@18 483 break;
universe@18 484 case INVALID_POSITION:
universe@18 485 printw("Cannot find the piece that shall be moved.");
universe@18 486 break;
universe@18 487 case NEED_PROMOTION:
universe@18 488 printw("You need to promote the pawn (append \"=Q\" e.g.)!");
universe@18 489 break;
universe@18 490 default:
universe@18 491 printw("Can't interpret move - please use algebraic notation.");
universe@8 492 }
universe@16 493 clrtoeol();
universe@7 494 }
universe@7 495 }
universe@7 496 }
universe@7 497
universe@18 498 static int recvmove(Board board, MoveListRoot *movelist, int opponent) {
universe@7 499
universe@18 500 int inputy = getmaxy(tchess_window) - 6;
universe@7 501 while (1) {
universe@18 502 move(inputy, 0);
universe@7 503 printw("Awaiting opponent move...");
universe@7 504 clrtoeol();
universe@7 505 refresh();
universe@7 506
universe@7 507 // TODO: nonblocking
universe@7 508 uint32_t code = net_recieve_code(opponent);
universe@8 509
universe@8 510 Move move;
universe@7 511 switch (code) {
universe@7 512 case NETCODE_SURRENDER:
universe@7 513 printw("\rYour opponent surrendered!");
universe@7 514 clrtoeol();
universe@7 515 return 1;
universe@7 516 case NETCODE_REMIS:
universe@7 517 if (prompt_yesno(
universe@7 518 "\rYour opponent offers remis - do you accept")) {
universe@7 519 printw("\rRemis accepted!");
universe@7 520 clrtoeol();
universe@7 521 net_send_code(opponent, NETCODE_ACCEPT);
universe@7 522 return 1;
universe@7 523 } else {
universe@7 524 net_send_code(opponent, NETCODE_DECLINE);
universe@7 525 }
universe@7 526 break;
universe@7 527 case NETCODE_MOVE:
universe@8 528 net_recieve_data(opponent, &move, sizeof(Move));
universe@11 529 if (validate_move(board, &move)) {
universe@8 530 apply_move(board, &move);
universe@18 531 addmove(movelist, &move);
universe@11 532 if (move.check) {
universe@11 533 net_send_code(opponent, NETCODE_CHECK);
universe@11 534 } else if (move.checkmate) {
universe@11 535 net_send_code(opponent, NETCODE_CHECKMATE);
universe@11 536 } else {
universe@11 537 net_send_code(opponent, NETCODE_ACCEPT);
universe@11 538 }
universe@8 539 return 0;
universe@8 540 } else {
universe@8 541 net_send_code(opponent, NETCODE_DECLINE);
universe@8 542 }
universe@7 543 }
universe@7 544 }
universe@7 545 }
universe@6 546
universe@18 547 void freemovelist(MoveListRoot* list) {
universe@18 548 MoveList *elem;
universe@18 549 elem = list->first;
universe@18 550 while (elem) {
universe@18 551 MoveList *cur = elem;
universe@18 552 elem = elem->next;
universe@18 553 free(cur);
universe@18 554 };
universe@18 555 free(list);
universe@18 556 }
universe@18 557
universe@18 558 void addmove(MoveListRoot* list, Move *move) {
universe@18 559 MoveList *elem = malloc(sizeof(MoveList));
universe@18 560 elem->next = NULL;
universe@18 561 elem->move = *move;
universe@18 562
universe@18 563 if (list->last) {
universe@18 564 list->last->next = elem;
universe@18 565 list->last = elem;
universe@18 566 } else {
universe@18 567 list->first = list->last = elem;
universe@18 568 }
universe@18 569 }
universe@18 570
universe@6 571 void game_start(Settings *settings, int opponent) {
universe@7 572 _Bool myturn = is_server(settings) ==
universe@7 573 (settings->gameinfo.servercolor == WHITE);
universe@8 574 uint8_t mycolor = myturn ? WHITE:BLACK;
universe@8 575
universe@7 576 _Bool running;
universe@6 577
universe@18 578 MoveListRoot* movelist = calloc(1, sizeof(MoveListRoot));
universe@18 579
universe@7 580 Board board = {
universe@7 581 {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
universe@7 582 {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN},
universe@7 583 {0, 0, 0, 0, 0, 0, 0, 0},
universe@7 584 {0, 0, 0, 0, 0, 0, 0, 0},
universe@7 585 {0, 0, 0, 0, 0, 0, 0, 0},
universe@7 586 {0, 0, 0, 0, 0, 0, 0, 0},
universe@7 587 {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN},
universe@7 588 {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
universe@7 589 };
universe@7 590
universe@7 591 do {
universe@7 592 clear();
universe@18 593 draw_board(board, movelist, mycolor);
universe@7 594 if (myturn) {
universe@18 595 running = !sendmove(board, movelist, mycolor, opponent);
universe@7 596 } else {
universe@18 597 running = !recvmove(board, movelist, opponent);
universe@7 598 flushinp(); // flush any input the user hacked in while waiting
universe@7 599 }
universe@11 600 myturn ^= TRUE;
universe@7 601 } while (running);
universe@7 602
universe@18 603 freemovelist(movelist);
universe@18 604
universe@7 605 mvaddstr(getmaxy(tchess_window)-1, 0,
universe@7 606 "Game has ended. Press any key to leave...");
universe@7 607 getch();
universe@6 608 }

mercurial