--- a/test/bigtestfile.c Mon Oct 03 12:27:10 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,808 +0,0 @@ -/* - * 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 "rules.h" -#include "chess.h" -#include <string.h> -#include <stdlib.h> -#include <sys/time.h> - -static GameState gamestate_copy_sim(GameState *gamestate) { - GameState simulation = *gamestate; - if (simulation.lastmove) { - MoveList *lastmovecopy = malloc(sizeof(MoveList)); - *lastmovecopy = *(simulation.lastmove); - simulation.movelist = simulation.lastmove = lastmovecopy; - } - - return simulation; -} - -void gamestate_init(GameState *gamestate) { - memset(gamestate, 0, sizeof(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)); -} - -void gamestate_cleanup(GameState *gamestate) { - MoveList *elem; - elem = gamestate->movelist; - while (elem) { - MoveList *cur = elem; - elem = elem->next; - free(cur); - }; -} - -/* MUST be called IMMEDIATLY after applying a move to work correctly */ -static void format_move(GameState *gamestate, Move *move) { - char *string = move->string; - - /* at least 8 characters should be available, wipe them out */ - memset(string, 0, 8); - - /* special formats for castling */ - if ((move->piece&PIECE_MASK) == KING && - abs(move->tofile-move->fromfile) == 2) { - if (move->tofile==fileidx('c')) { - memcpy(string, "O-O-O", 5); - } else { - memcpy(string, "O-O", 3); - } - } - - /* start by notating the piece character */ - string[0] = getpiecechr(move->piece); - int idx = string[0] ? 1 : 0; - - /* find out how many source information we do need */ - uint8_t piece = move->piece & PIECE_MASK; - if (piece == PAWN) { - if (move->capture) { - string[idx++] = filechr(move->fromfile); - } - } else if (piece != KING) { - Move threats[16]; - uint8_t threatcount; - get_real_threats(gamestate, move->torow, move->tofile, - move->piece&COLOR_MASK, threats, &threatcount); - if (threatcount > 1) { - int ambrows = 0, ambfiles = 0; - for (uint8_t i = 0 ; i < threatcount ; i++) { - if (threats[i].fromrow == move->fromrow) { - ambrows++; - } - if (threats[i].fromfile == move->fromfile) { - ambfiles++; - } - } - /* ambiguous row, name file */ - if (ambrows > 1) { - string[idx++] = filechr(move->fromfile); - } - /* ambiguous file, name row */ - if (ambfiles > 1) { - string[idx++] = filechr(move->fromrow); - } - } - } - - /* capturing? */ - if (move->capture) { - string[idx++] = 'x'; - } - - /* destination */ - string[idx++] = filechr(move->tofile); - string[idx++] = rowchr(move->torow); - - /* promotion? */ - if (move->promotion) { - string[idx++] = '='; - string[idx++] = getpiecechr(move->promotion); - } - - /* check? */ - if (move->check) { - /* works only, if this function is called when applying the move */ - string[idx++] = gamestate->checkmate?'#':'+'; - } -} - -static void addmove(GameState* gamestate, Move *move) { - MoveList *elem = malloc(sizeof(MoveList)); - elem->next = NULL; - elem->move = *move; - - struct timeval curtimestamp; - gettimeofday(&curtimestamp, NULL); - elem->move.timestamp.tv_sec = curtimestamp.tv_sec; - elem->move.timestamp.tv_usec = curtimestamp.tv_usec; - - if (gamestate->lastmove) { - struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp); - uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec; - suseconds_t micros; - if (curtimestamp.tv_usec < lasttstamp->tv_usec) { - micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec); - sec--; - } else { - micros = curtimestamp.tv_usec - lasttstamp->tv_usec; - } - - elem->move.movetime.tv_sec = sec; - elem->move.movetime.tv_usec = micros; - - gamestate->lastmove->next = elem; - gamestate->lastmove = elem; - } else { - elem->move.movetime.tv_usec = 0; - elem->move.movetime.tv_sec = 0; - gamestate->movelist = gamestate->lastmove = elem; - } -} - -char getpiecechr(uint8_t piece) { - switch (piece & PIECE_MASK) { - case ROOK: return 'R'; - case KNIGHT: return 'N'; - case BISHOP: return 'B'; - case QUEEN: return 'Q'; - case KING: return 'K'; - default: return '\0'; - } -} - -uint8_t getpiece(char c) { - switch (c) { - case 'R': return ROOK; - case 'N': return KNIGHT; - case 'B': return BISHOP; - case 'Q': return QUEEN; - case 'K': return KING; - default: return 0; - } -} - -static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) { - uint8_t piece = move->piece & PIECE_MASK; - uint8_t color = move->piece & COLOR_MASK; - - /* en passant capture */ - if (move->capture && piece == PAWN && - mdst(gamestate->board, move) == 0) { - gamestate->board[move->fromrow][move->tofile] = 0; - } - - /* remove old en passant threats */ - for (uint8_t file = 0 ; file < 8 ; file++) { - gamestate->board[3][file] &= ~ENPASSANT_THREAT; - gamestate->board[4][file] &= ~ENPASSANT_THREAT; - } - - /* add new en passant threat */ - if (piece == PAWN && ( - (move->fromrow == 1 && move->torow == 3) || - (move->fromrow == 6 && move->torow == 4))) { - move->piece |= ENPASSANT_THREAT; - } - - /* move (and maybe capture or promote) */ - msrc(gamestate->board, move) = 0; - if (move->promotion) { - mdst(gamestate->board, move) = move->promotion; - } else { - mdst(gamestate->board, move) = move->piece; - } - - /* castling */ - if (piece == KING && move->fromfile == fileidx('e')) { - - if (move->tofile == fileidx('g')) { - gamestate->board[move->torow][fileidx('h')] = 0; - gamestate->board[move->torow][fileidx('f')] = color|ROOK; - } else if (move->tofile == fileidx('c')) { - gamestate->board[move->torow][fileidx('a')] = 0; - gamestate->board[move->torow][fileidx('d')] = color|ROOK; - } - } - - if (!simulate) { - if (!move->string[0]) { - format_move(gamestate, move); - } - } - /* add move, even in simulation (checkmate test needs it) */ - addmove(gamestate, move); -} - -void apply_move(GameState *gamestate, Move *move) { - apply_move_impl(gamestate, move, 0); -} - -static int validate_move_rules(GameState *gamestate, Move *move) { - /* validate indices (don't trust opponent) */ - if (!chkidx(move)) { - return INVALID_POSITION; - } - - /* must move */ - if (move->fromfile == move->tofile && move->fromrow == move->torow) { - return INVALID_MOVE_SYNTAX; - } - - /* does piece exist */ - if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) - != (move->piece&(PIECE_MASK|COLOR_MASK))) { - return INVALID_POSITION; - } - - /* can't capture own pieces */ - if ((mdst(gamestate->board, move) & COLOR_MASK) - == (move->piece & COLOR_MASK)) { - return RULES_VIOLATED; - } - - /* must capture, if and only if destination is occupied */ - if ((mdst(gamestate->board, move) == 0 && move->capture) || - (mdst(gamestate->board, move) != 0 && !move->capture)) { - return INVALID_MOVE_SYNTAX; - } - - /* validate individual rules */ - _Bool chkrules; - switch (move->piece & PIECE_MASK) { - case PAWN: - chkrules = pawn_chkrules(gamestate, move) && - !pawn_isblocked(gamestate, move); - break; - case ROOK: - chkrules = rook_chkrules(move) && - !rook_isblocked(gamestate, move); - break; - case KNIGHT: - chkrules = knight_chkrules(move); /* knight is never blocked */ - break; - case BISHOP: - chkrules = bishop_chkrules(move) && - !bishop_isblocked(gamestate, move); - break; - case QUEEN: - chkrules = queen_chkrules(move) && - !queen_isblocked(gamestate, move); - break; - case KING: - chkrules = king_chkrules(gamestate, move) && - !king_isblocked(gamestate, move); - break; - default: - return INVALID_MOVE_SYNTAX; - } - - return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED; -} - -int validate_move(GameState *gamestate, Move *move) { - - int result = validate_move_rules(gamestate, move); - - /* cancel processing to save resources */ - if (result != VALID_MOVE_SEMANTICS) { - return result; - } - - /* find kings for check validation */ - uint8_t piececolor = (move->piece & COLOR_MASK); - - uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; - for (uint8_t row = 0 ; row < 8 ; row++) { - for (uint8_t file = 0 ; file < 8 ; file++) { - if (gamestate->board[row][file] == - (piececolor == WHITE?WKING:BKING)) { - mykingfile = file; - mykingrow = row; - } else if (gamestate->board[row][file] == - (piececolor == WHITE?BKING:WKING)) { - opkingfile = file; - opkingrow = row; - } - } - } - - /* simulate move for check validation */ - GameState simulation = gamestate_copy_sim(gamestate); - Move simmove = *move; - apply_move_impl(&simulation, &simmove, 1); - - /* don't move into or stay in check position */ - if (is_covered(&simulation, mykingrow, mykingfile, - opponent_color(piececolor))) { - - gamestate_cleanup(&simulation); - if ((move->piece & PIECE_MASK) == KING) { - return KING_MOVES_INTO_CHECK; - } else { - /* last move is always not null in this case */ - return gamestate->lastmove->move.check ? - KING_IN_CHECK : PIECE_PINNED; - } - } - - /* correct check and checkmate flags (move is still valid) */ - Move threats[16]; - uint8_t threatcount; - move->check = get_threats(&simulation, opkingrow, opkingfile, - piececolor, threats, &threatcount); - - if (move->check) { - /* determine possible escape fields */ - _Bool canescape = 0; - for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { - for (int df = -1 ; df <= 1 && !canescape ; df++) { - if (!(dr == 0 && df == 0) && - isidx(opkingrow + dr) && isidx(opkingfile + df)) { - - /* escape field neither blocked nor covered */ - if ((simulation.board[opkingrow + dr][opkingfile + df] - & COLOR_MASK) != opponent_color(piececolor)) { - canescape |= !is_covered(&simulation, - opkingrow + dr, opkingfile + df, piececolor); - } - } - } - } - /* can't escape, can he capture? */ - if (!canescape && threatcount == 1) { - canescape = is_attacked(&simulation, threats[0].fromrow, - threats[0].fromfile, opponent_color(piececolor)); - } - - /* can't capture, can he block? */ - if (!canescape && threatcount == 1) { - Move *threat = &(threats[0]); - uint8_t threatpiece = threat->piece & PIECE_MASK; - - /* knight, pawns and the king cannot be blocked */ - if (threatpiece == BISHOP || threatpiece == ROOK - || threatpiece == QUEEN) { - if (threat->fromrow == threat->torow) { - /* rook aspect (on row) */ - int d = threat->tofile > threat->fromfile ? 1 : -1; - uint8_t file = threat->fromfile; - while (!canescape && file != threat->tofile - d) { - file += d; - canescape |= is_protected(&simulation, - threat->torow, file, opponent_color(piececolor)); - } - } else if (threat->fromfile == threat->tofile) { - /* rook aspect (on file) */ - int d = threat->torow > threat->fromrow ? 1 : -1; - uint8_t row = threat->fromrow; - while (!canescape && row != threat->torow - d) { - row += d; - canescape |= is_protected(&simulation, - row, threat->tofile, opponent_color(piececolor)); - } - } else { - /* bishop aspect */ - int dr = threat->torow > threat->fromrow ? 1 : -1; - int df = threat->tofile > threat->fromfile ? 1 : -1; - - uint8_t row = threat->fromrow; - uint8_t file = threat->fromfile; - while (!canescape && file != threat->tofile - df - && row != threat->torow - dr) { - row += dr; - file += df; - canescape |= is_protected(&simulation, row, file, - opponent_color(piececolor)); - } - } - } - } - - if (!canescape) { - gamestate->checkmate = 1; - } - } - - gamestate_cleanup(&simulation); - - return VALID_MOVE_SEMANTICS; -} - -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - Move candidates[32]; - int candidatecount = 0; - for (uint8_t r = 0 ; r < 8 ; r++) { - for (uint8_t f = 0 ; f < 8 ; f++) { - if ((gamestate->board[r][f] & COLOR_MASK) == color) { - // non-capturing move - memset(&(candidates[candidatecount]), 0, sizeof(Move)); - candidates[candidatecount].piece = gamestate->board[r][f]; - candidates[candidatecount].fromrow = r; - candidates[candidatecount].fromfile = f; - candidates[candidatecount].torow = row; - candidates[candidatecount].tofile = file; - candidatecount++; - - // capturing move - memcpy(&(candidates[candidatecount]), - &(candidates[candidatecount-1]), sizeof(Move)); - candidates[candidatecount].capture = 1; - candidatecount++; - } - } - } - - if (threatcount) { - *threatcount = 0; - } - - - _Bool result = 0; - - for (int i = 0 ; i < candidatecount ; i++) { - if (validate_move_rules(gamestate, &(candidates[i])) - == VALID_MOVE_SEMANTICS) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; -} - -_Bool is_pinned(GameState *gamestate, Move *move) { - uint8_t color = move->piece & COLOR_MASK; - - uint8_t kingfile = 0, kingrow = 0; - for (uint8_t row = 0 ; row < 8 ; row++) { - for (uint8_t file = 0 ; file < 8 ; file++) { - if (gamestate->board[row][file] == (color|KING)) { - kingfile = file; - kingrow = row; - } - } - } - - GameState simulation = gamestate_copy_sim(gamestate); - Move simmove = *move; - apply_move(&simulation, &simmove); - _Bool covered = is_covered(&simulation, - kingrow, kingfile, opponent_color(color)); - gamestate_cleanup(&simulation); - - return covered; -} - -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - - if (threatcount) { - *threatcount = 0; - } - - Move candidates[16]; - uint8_t candidatecount; - if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { - - _Bool result = 0; - uint8_t kingfile = 0, kingrow = 0; - for (uint8_t row = 0 ; row < 8 ; row++) { - for (uint8_t file = 0 ; file < 8 ; file++) { - if (gamestate->board[row][file] == (color|KING)) { - kingfile = file; - kingrow = row; - } - } - } - - for (uint8_t i = 0 ; i < candidatecount ; i++) { - GameState simulation = gamestate_copy_sim(gamestate); - Move simmove = candidates[i]; - apply_move(&simulation, &simmove); - if (!is_covered(&simulation, kingrow, kingfile, - opponent_color(color))) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; - } else { - return 0; - } -} - -static int getlocation(GameState *gamestate, Move *move) { - - uint8_t color = move->piece & COLOR_MASK; - _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; - - Move threats[16], *threat = NULL; - uint8_t threatcount; - - if (get_threats(gamestate, move->torow, move->tofile, color, - threats, &threatcount)) { - - int reason = INVALID_POSITION; - - // find threats for the specified position - for (uint8_t i = 0 ; i < threatcount ; i++) { - if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) - == move->piece && - (move->fromrow == POS_UNSPECIFIED || - move->fromrow == threats[i].fromrow) && - (move->fromfile == POS_UNSPECIFIED || - move->fromfile == threats[i].fromfile)) { - - if (threat) { - return AMBIGUOUS_MOVE; - } else { - // found threat is no real threat - if (is_pinned(gamestate, &(threats[i]))) { - reason = incheck?KING_IN_CHECK:PIECE_PINNED; - } else { - threat = &(threats[i]); - } - } - } - } - - // can't threaten specified position - if (!threat) { - return reason; - } - - memcpy(move, threat, sizeof(Move)); - return VALID_MOVE_SYNTAX; - } else { - return INVALID_POSITION; - } -} - -int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) { - memset(move, 0, sizeof(Move)); - move->fromfile = POS_UNSPECIFIED; - move->fromrow = POS_UNSPECIFIED; - - size_t len = strlen(mstr); - if (len < 1 || len > 6) { - return INVALID_MOVE_SYNTAX; - } - - /* evaluate check/checkmate flags */ - if (mstr[len-1] == '+') { - len--; mstr[len] = '\0'; - move->check = 1; - } else if (mstr[len-1] == '#') { - len--; mstr[len] = '\0'; - /* ignore - validation should set game state */ - } - - /* evaluate promotion */ - if (len > 3 && mstr[len-2] == '=') { - move->promotion = getpiece(mstr[len-1]); - if (!move->promotion) { - return INVALID_MOVE_SYNTAX; - } else { - move->promotion |= color; - len -= 2; - mstr[len] = 0; - } - } - - if (len == 2) { - /* pawn move (e.g. "e4") */ - move->piece = PAWN; - move->tofile = fileidx(mstr[0]); - move->torow = rowidx(mstr[1]); - } else if (len == 3) { - if (strcmp(mstr, "O-O") == 0) { - /* king side castling */ - move->piece = KING; - move->fromfile = fileidx('e'); - move->tofile = fileidx('g'); - move->fromrow = move->torow = color == WHITE ? 0 : 7; - } else { - /* move (e.g. "Nf3") */ - move->piece = getpiece(mstr[0]); - move->tofile = fileidx(mstr[1]); - move->torow = rowidx(mstr[2]); - } - } else if (len == 4) { - move->piece = getpiece(mstr[0]); - if (!move->piece) { - move->piece = PAWN; - move->fromfile = fileidx(mstr[0]); - } - if (mstr[1] == 'x') { - /* capture (e.g. "Nxf3", "dxe5") */ - move->capture = 1; - } else { - /* move (e.g. "Ndf3", "N2c3", "e2e4") */ - if (isfile(mstr[1])) { - move->fromfile = fileidx(mstr[1]); - if (move->piece == PAWN) { - move->piece = 0; - } - } else { - move->fromrow = rowidx(mstr[1]); - } - } - move->tofile = fileidx(mstr[2]); - move->torow = rowidx(mstr[3]); - } else if (len == 5) { - if (strcmp(mstr, "O-O-O") == 0) { - /* queen side castling "O-O-O" */ - move->piece = KING; - move->fromfile = fileidx('e'); - move->tofile = fileidx('c'); - move->fromrow = move->torow = color == WHITE ? 0 : 7; - } else { - move->piece = getpiece(mstr[0]); - if (mstr[2] == 'x') { - move->capture = 1; - if (move->piece) { - /* capture (e.g. "Ndxf3") */ - move->fromfile = fileidx(mstr[1]); - } else { - /* long notation capture (e.g. "e5xf6") */ - move->piece = PAWN; - move->fromfile = fileidx(mstr[0]); - move->fromrow = rowidx(mstr[1]); - } - } else { - /* long notation move (e.g. "Nc5a4") */ - move->fromfile = fileidx(mstr[1]); - move->fromrow = rowidx(mstr[2]); - } - move->tofile = fileidx(mstr[3]); - move->torow = rowidx(mstr[4]); - } - } else if (len == 6) { - /* long notation capture (e.g. "Nc5xf3") */ - if (mstr[3] == 'x') { - move->capture = 1; - move->piece = getpiece(mstr[0]); - move->fromfile = fileidx(mstr[1]); - move->fromrow = rowidx(mstr[2]); - move->tofile = fileidx(mstr[4]); - move->torow = rowidx(mstr[5]); - } - } - - - if (move->piece) { - if (move->piece == PAWN - && move->torow == (color==WHITE?7:0) - && !move->promotion) { - return NEED_PROMOTION; - } - - move->piece |= color; - if (move->fromfile == POS_UNSPECIFIED - || move->fromrow == POS_UNSPECIFIED) { - return getlocation(gamestate, move); - } else { - return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION; - } - } else { - return INVALID_MOVE_SYNTAX; - } -} - -_Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color) { - - Move threats[16]; - uint8_t threatcount; - if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) { - for (int i = 0 ; i < threatcount ; i++) { - if (threats[i].piece != (color|KING)) { - return 1; - } - } - return 0; - } else { - return 0; - } -} - -uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, - uint8_t color) { - if (!gameinfo->timecontrol) { - return 0; - } - - if (gamestate->movelist) { - uint16_t time = gameinfo->time; - suseconds_t micros = 0; - - MoveList *movelist = color == WHITE ? - gamestate->movelist : gamestate->movelist->next; - - while (movelist) { - time += gameinfo->addtime; - - struct movetimeval *movetime = &(movelist->move.movetime); - if (movetime->tv_sec >= time) { - return 0; - } - - time -= movetime->tv_sec; - micros += movetime->tv_usec; - - movelist = movelist->next ? movelist->next->next : NULL; - } - - time_t sec; - movelist = gamestate->lastmove; - if ((movelist->move.piece & COLOR_MASK) != color) { - struct movetimeval *lastmovetstamp = &(movelist->move.timestamp); - struct timeval currenttstamp; - gettimeofday(¤ttstamp, NULL); - micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec; - sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec; - if (sec >= time) { - return 0; - } - - time -= sec; - } - - sec = micros / 1e6L; - - if (sec >= time) { - return 0; - } - - time -= sec; - - return time; - } else { - return gameinfo->time; - } -}