1.1 --- a/test/bigtestfile.c Mon Oct 03 12:27:10 2022 +0200 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,808 +0,0 @@ 1.4 -/* 1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 - * 1.7 - * Copyright 2014 Mike Becker. All rights reserved. 1.8 - * 1.9 - * Redistribution and use in source and binary forms, with or without 1.10 - * modification, are permitted provided that the following conditions are met: 1.11 - * 1.12 - * 1. Redistributions of source code must retain the above copyright 1.13 - * notice, this list of conditions and the following disclaimer. 1.14 - * 1.15 - * 2. Redistributions in binary form must reproduce the above copyright 1.16 - * notice, this list of conditions and the following disclaimer in the 1.17 - * documentation and/or other materials provided with the distribution. 1.18 - * 1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 - * POSSIBILITY OF SUCH DAMAGE. 1.30 - * 1.31 - */ 1.32 - 1.33 -#include "rules.h" 1.34 -#include "chess.h" 1.35 -#include <string.h> 1.36 -#include <stdlib.h> 1.37 -#include <sys/time.h> 1.38 - 1.39 -static GameState gamestate_copy_sim(GameState *gamestate) { 1.40 - GameState simulation = *gamestate; 1.41 - if (simulation.lastmove) { 1.42 - MoveList *lastmovecopy = malloc(sizeof(MoveList)); 1.43 - *lastmovecopy = *(simulation.lastmove); 1.44 - simulation.movelist = simulation.lastmove = lastmovecopy; 1.45 - } 1.46 - 1.47 - return simulation; 1.48 -} 1.49 - 1.50 -void gamestate_init(GameState *gamestate) { 1.51 - memset(gamestate, 0, sizeof(GameState)); 1.52 - 1.53 - Board initboard = { 1.54 - {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK}, 1.55 - {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN}, 1.56 - {0, 0, 0, 0, 0, 0, 0, 0}, 1.57 - {0, 0, 0, 0, 0, 0, 0, 0}, 1.58 - {0, 0, 0, 0, 0, 0, 0, 0}, 1.59 - {0, 0, 0, 0, 0, 0, 0, 0}, 1.60 - {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN}, 1.61 - {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK} 1.62 - }; 1.63 - memcpy(gamestate->board, initboard, sizeof(Board)); 1.64 -} 1.65 - 1.66 -void gamestate_cleanup(GameState *gamestate) { 1.67 - MoveList *elem; 1.68 - elem = gamestate->movelist; 1.69 - while (elem) { 1.70 - MoveList *cur = elem; 1.71 - elem = elem->next; 1.72 - free(cur); 1.73 - }; 1.74 -} 1.75 - 1.76 -/* MUST be called IMMEDIATLY after applying a move to work correctly */ 1.77 -static void format_move(GameState *gamestate, Move *move) { 1.78 - char *string = move->string; 1.79 - 1.80 - /* at least 8 characters should be available, wipe them out */ 1.81 - memset(string, 0, 8); 1.82 - 1.83 - /* special formats for castling */ 1.84 - if ((move->piece&PIECE_MASK) == KING && 1.85 - abs(move->tofile-move->fromfile) == 2) { 1.86 - if (move->tofile==fileidx('c')) { 1.87 - memcpy(string, "O-O-O", 5); 1.88 - } else { 1.89 - memcpy(string, "O-O", 3); 1.90 - } 1.91 - } 1.92 - 1.93 - /* start by notating the piece character */ 1.94 - string[0] = getpiecechr(move->piece); 1.95 - int idx = string[0] ? 1 : 0; 1.96 - 1.97 - /* find out how many source information we do need */ 1.98 - uint8_t piece = move->piece & PIECE_MASK; 1.99 - if (piece == PAWN) { 1.100 - if (move->capture) { 1.101 - string[idx++] = filechr(move->fromfile); 1.102 - } 1.103 - } else if (piece != KING) { 1.104 - Move threats[16]; 1.105 - uint8_t threatcount; 1.106 - get_real_threats(gamestate, move->torow, move->tofile, 1.107 - move->piece&COLOR_MASK, threats, &threatcount); 1.108 - if (threatcount > 1) { 1.109 - int ambrows = 0, ambfiles = 0; 1.110 - for (uint8_t i = 0 ; i < threatcount ; i++) { 1.111 - if (threats[i].fromrow == move->fromrow) { 1.112 - ambrows++; 1.113 - } 1.114 - if (threats[i].fromfile == move->fromfile) { 1.115 - ambfiles++; 1.116 - } 1.117 - } 1.118 - /* ambiguous row, name file */ 1.119 - if (ambrows > 1) { 1.120 - string[idx++] = filechr(move->fromfile); 1.121 - } 1.122 - /* ambiguous file, name row */ 1.123 - if (ambfiles > 1) { 1.124 - string[idx++] = filechr(move->fromrow); 1.125 - } 1.126 - } 1.127 - } 1.128 - 1.129 - /* capturing? */ 1.130 - if (move->capture) { 1.131 - string[idx++] = 'x'; 1.132 - } 1.133 - 1.134 - /* destination */ 1.135 - string[idx++] = filechr(move->tofile); 1.136 - string[idx++] = rowchr(move->torow); 1.137 - 1.138 - /* promotion? */ 1.139 - if (move->promotion) { 1.140 - string[idx++] = '='; 1.141 - string[idx++] = getpiecechr(move->promotion); 1.142 - } 1.143 - 1.144 - /* check? */ 1.145 - if (move->check) { 1.146 - /* works only, if this function is called when applying the move */ 1.147 - string[idx++] = gamestate->checkmate?'#':'+'; 1.148 - } 1.149 -} 1.150 - 1.151 -static void addmove(GameState* gamestate, Move *move) { 1.152 - MoveList *elem = malloc(sizeof(MoveList)); 1.153 - elem->next = NULL; 1.154 - elem->move = *move; 1.155 - 1.156 - struct timeval curtimestamp; 1.157 - gettimeofday(&curtimestamp, NULL); 1.158 - elem->move.timestamp.tv_sec = curtimestamp.tv_sec; 1.159 - elem->move.timestamp.tv_usec = curtimestamp.tv_usec; 1.160 - 1.161 - if (gamestate->lastmove) { 1.162 - struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp); 1.163 - uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec; 1.164 - suseconds_t micros; 1.165 - if (curtimestamp.tv_usec < lasttstamp->tv_usec) { 1.166 - micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec); 1.167 - sec--; 1.168 - } else { 1.169 - micros = curtimestamp.tv_usec - lasttstamp->tv_usec; 1.170 - } 1.171 - 1.172 - elem->move.movetime.tv_sec = sec; 1.173 - elem->move.movetime.tv_usec = micros; 1.174 - 1.175 - gamestate->lastmove->next = elem; 1.176 - gamestate->lastmove = elem; 1.177 - } else { 1.178 - elem->move.movetime.tv_usec = 0; 1.179 - elem->move.movetime.tv_sec = 0; 1.180 - gamestate->movelist = gamestate->lastmove = elem; 1.181 - } 1.182 -} 1.183 - 1.184 -char getpiecechr(uint8_t piece) { 1.185 - switch (piece & PIECE_MASK) { 1.186 - case ROOK: return 'R'; 1.187 - case KNIGHT: return 'N'; 1.188 - case BISHOP: return 'B'; 1.189 - case QUEEN: return 'Q'; 1.190 - case KING: return 'K'; 1.191 - default: return '\0'; 1.192 - } 1.193 -} 1.194 - 1.195 -uint8_t getpiece(char c) { 1.196 - switch (c) { 1.197 - case 'R': return ROOK; 1.198 - case 'N': return KNIGHT; 1.199 - case 'B': return BISHOP; 1.200 - case 'Q': return QUEEN; 1.201 - case 'K': return KING; 1.202 - default: return 0; 1.203 - } 1.204 -} 1.205 - 1.206 -static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) { 1.207 - uint8_t piece = move->piece & PIECE_MASK; 1.208 - uint8_t color = move->piece & COLOR_MASK; 1.209 - 1.210 - /* en passant capture */ 1.211 - if (move->capture && piece == PAWN && 1.212 - mdst(gamestate->board, move) == 0) { 1.213 - gamestate->board[move->fromrow][move->tofile] = 0; 1.214 - } 1.215 - 1.216 - /* remove old en passant threats */ 1.217 - for (uint8_t file = 0 ; file < 8 ; file++) { 1.218 - gamestate->board[3][file] &= ~ENPASSANT_THREAT; 1.219 - gamestate->board[4][file] &= ~ENPASSANT_THREAT; 1.220 - } 1.221 - 1.222 - /* add new en passant threat */ 1.223 - if (piece == PAWN && ( 1.224 - (move->fromrow == 1 && move->torow == 3) || 1.225 - (move->fromrow == 6 && move->torow == 4))) { 1.226 - move->piece |= ENPASSANT_THREAT; 1.227 - } 1.228 - 1.229 - /* move (and maybe capture or promote) */ 1.230 - msrc(gamestate->board, move) = 0; 1.231 - if (move->promotion) { 1.232 - mdst(gamestate->board, move) = move->promotion; 1.233 - } else { 1.234 - mdst(gamestate->board, move) = move->piece; 1.235 - } 1.236 - 1.237 - /* castling */ 1.238 - if (piece == KING && move->fromfile == fileidx('e')) { 1.239 - 1.240 - if (move->tofile == fileidx('g')) { 1.241 - gamestate->board[move->torow][fileidx('h')] = 0; 1.242 - gamestate->board[move->torow][fileidx('f')] = color|ROOK; 1.243 - } else if (move->tofile == fileidx('c')) { 1.244 - gamestate->board[move->torow][fileidx('a')] = 0; 1.245 - gamestate->board[move->torow][fileidx('d')] = color|ROOK; 1.246 - } 1.247 - } 1.248 - 1.249 - if (!simulate) { 1.250 - if (!move->string[0]) { 1.251 - format_move(gamestate, move); 1.252 - } 1.253 - } 1.254 - /* add move, even in simulation (checkmate test needs it) */ 1.255 - addmove(gamestate, move); 1.256 -} 1.257 - 1.258 -void apply_move(GameState *gamestate, Move *move) { 1.259 - apply_move_impl(gamestate, move, 0); 1.260 -} 1.261 - 1.262 -static int validate_move_rules(GameState *gamestate, Move *move) { 1.263 - /* validate indices (don't trust opponent) */ 1.264 - if (!chkidx(move)) { 1.265 - return INVALID_POSITION; 1.266 - } 1.267 - 1.268 - /* must move */ 1.269 - if (move->fromfile == move->tofile && move->fromrow == move->torow) { 1.270 - return INVALID_MOVE_SYNTAX; 1.271 - } 1.272 - 1.273 - /* does piece exist */ 1.274 - if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) 1.275 - != (move->piece&(PIECE_MASK|COLOR_MASK))) { 1.276 - return INVALID_POSITION; 1.277 - } 1.278 - 1.279 - /* can't capture own pieces */ 1.280 - if ((mdst(gamestate->board, move) & COLOR_MASK) 1.281 - == (move->piece & COLOR_MASK)) { 1.282 - return RULES_VIOLATED; 1.283 - } 1.284 - 1.285 - /* must capture, if and only if destination is occupied */ 1.286 - if ((mdst(gamestate->board, move) == 0 && move->capture) || 1.287 - (mdst(gamestate->board, move) != 0 && !move->capture)) { 1.288 - return INVALID_MOVE_SYNTAX; 1.289 - } 1.290 - 1.291 - /* validate individual rules */ 1.292 - _Bool chkrules; 1.293 - switch (move->piece & PIECE_MASK) { 1.294 - case PAWN: 1.295 - chkrules = pawn_chkrules(gamestate, move) && 1.296 - !pawn_isblocked(gamestate, move); 1.297 - break; 1.298 - case ROOK: 1.299 - chkrules = rook_chkrules(move) && 1.300 - !rook_isblocked(gamestate, move); 1.301 - break; 1.302 - case KNIGHT: 1.303 - chkrules = knight_chkrules(move); /* knight is never blocked */ 1.304 - break; 1.305 - case BISHOP: 1.306 - chkrules = bishop_chkrules(move) && 1.307 - !bishop_isblocked(gamestate, move); 1.308 - break; 1.309 - case QUEEN: 1.310 - chkrules = queen_chkrules(move) && 1.311 - !queen_isblocked(gamestate, move); 1.312 - break; 1.313 - case KING: 1.314 - chkrules = king_chkrules(gamestate, move) && 1.315 - !king_isblocked(gamestate, move); 1.316 - break; 1.317 - default: 1.318 - return INVALID_MOVE_SYNTAX; 1.319 - } 1.320 - 1.321 - return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED; 1.322 -} 1.323 - 1.324 -int validate_move(GameState *gamestate, Move *move) { 1.325 - 1.326 - int result = validate_move_rules(gamestate, move); 1.327 - 1.328 - /* cancel processing to save resources */ 1.329 - if (result != VALID_MOVE_SEMANTICS) { 1.330 - return result; 1.331 - } 1.332 - 1.333 - /* find kings for check validation */ 1.334 - uint8_t piececolor = (move->piece & COLOR_MASK); 1.335 - 1.336 - uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; 1.337 - for (uint8_t row = 0 ; row < 8 ; row++) { 1.338 - for (uint8_t file = 0 ; file < 8 ; file++) { 1.339 - if (gamestate->board[row][file] == 1.340 - (piececolor == WHITE?WKING:BKING)) { 1.341 - mykingfile = file; 1.342 - mykingrow = row; 1.343 - } else if (gamestate->board[row][file] == 1.344 - (piececolor == WHITE?BKING:WKING)) { 1.345 - opkingfile = file; 1.346 - opkingrow = row; 1.347 - } 1.348 - } 1.349 - } 1.350 - 1.351 - /* simulate move for check validation */ 1.352 - GameState simulation = gamestate_copy_sim(gamestate); 1.353 - Move simmove = *move; 1.354 - apply_move_impl(&simulation, &simmove, 1); 1.355 - 1.356 - /* don't move into or stay in check position */ 1.357 - if (is_covered(&simulation, mykingrow, mykingfile, 1.358 - opponent_color(piececolor))) { 1.359 - 1.360 - gamestate_cleanup(&simulation); 1.361 - if ((move->piece & PIECE_MASK) == KING) { 1.362 - return KING_MOVES_INTO_CHECK; 1.363 - } else { 1.364 - /* last move is always not null in this case */ 1.365 - return gamestate->lastmove->move.check ? 1.366 - KING_IN_CHECK : PIECE_PINNED; 1.367 - } 1.368 - } 1.369 - 1.370 - /* correct check and checkmate flags (move is still valid) */ 1.371 - Move threats[16]; 1.372 - uint8_t threatcount; 1.373 - move->check = get_threats(&simulation, opkingrow, opkingfile, 1.374 - piececolor, threats, &threatcount); 1.375 - 1.376 - if (move->check) { 1.377 - /* determine possible escape fields */ 1.378 - _Bool canescape = 0; 1.379 - for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { 1.380 - for (int df = -1 ; df <= 1 && !canescape ; df++) { 1.381 - if (!(dr == 0 && df == 0) && 1.382 - isidx(opkingrow + dr) && isidx(opkingfile + df)) { 1.383 - 1.384 - /* escape field neither blocked nor covered */ 1.385 - if ((simulation.board[opkingrow + dr][opkingfile + df] 1.386 - & COLOR_MASK) != opponent_color(piececolor)) { 1.387 - canescape |= !is_covered(&simulation, 1.388 - opkingrow + dr, opkingfile + df, piececolor); 1.389 - } 1.390 - } 1.391 - } 1.392 - } 1.393 - /* can't escape, can he capture? */ 1.394 - if (!canescape && threatcount == 1) { 1.395 - canescape = is_attacked(&simulation, threats[0].fromrow, 1.396 - threats[0].fromfile, opponent_color(piececolor)); 1.397 - } 1.398 - 1.399 - /* can't capture, can he block? */ 1.400 - if (!canescape && threatcount == 1) { 1.401 - Move *threat = &(threats[0]); 1.402 - uint8_t threatpiece = threat->piece & PIECE_MASK; 1.403 - 1.404 - /* knight, pawns and the king cannot be blocked */ 1.405 - if (threatpiece == BISHOP || threatpiece == ROOK 1.406 - || threatpiece == QUEEN) { 1.407 - if (threat->fromrow == threat->torow) { 1.408 - /* rook aspect (on row) */ 1.409 - int d = threat->tofile > threat->fromfile ? 1 : -1; 1.410 - uint8_t file = threat->fromfile; 1.411 - while (!canescape && file != threat->tofile - d) { 1.412 - file += d; 1.413 - canescape |= is_protected(&simulation, 1.414 - threat->torow, file, opponent_color(piececolor)); 1.415 - } 1.416 - } else if (threat->fromfile == threat->tofile) { 1.417 - /* rook aspect (on file) */ 1.418 - int d = threat->torow > threat->fromrow ? 1 : -1; 1.419 - uint8_t row = threat->fromrow; 1.420 - while (!canescape && row != threat->torow - d) { 1.421 - row += d; 1.422 - canescape |= is_protected(&simulation, 1.423 - row, threat->tofile, opponent_color(piececolor)); 1.424 - } 1.425 - } else { 1.426 - /* bishop aspect */ 1.427 - int dr = threat->torow > threat->fromrow ? 1 : -1; 1.428 - int df = threat->tofile > threat->fromfile ? 1 : -1; 1.429 - 1.430 - uint8_t row = threat->fromrow; 1.431 - uint8_t file = threat->fromfile; 1.432 - while (!canescape && file != threat->tofile - df 1.433 - && row != threat->torow - dr) { 1.434 - row += dr; 1.435 - file += df; 1.436 - canescape |= is_protected(&simulation, row, file, 1.437 - opponent_color(piececolor)); 1.438 - } 1.439 - } 1.440 - } 1.441 - } 1.442 - 1.443 - if (!canescape) { 1.444 - gamestate->checkmate = 1; 1.445 - } 1.446 - } 1.447 - 1.448 - gamestate_cleanup(&simulation); 1.449 - 1.450 - return VALID_MOVE_SEMANTICS; 1.451 -} 1.452 - 1.453 -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, 1.454 - uint8_t color, Move *threats, uint8_t *threatcount) { 1.455 - Move candidates[32]; 1.456 - int candidatecount = 0; 1.457 - for (uint8_t r = 0 ; r < 8 ; r++) { 1.458 - for (uint8_t f = 0 ; f < 8 ; f++) { 1.459 - if ((gamestate->board[r][f] & COLOR_MASK) == color) { 1.460 - // non-capturing move 1.461 - memset(&(candidates[candidatecount]), 0, sizeof(Move)); 1.462 - candidates[candidatecount].piece = gamestate->board[r][f]; 1.463 - candidates[candidatecount].fromrow = r; 1.464 - candidates[candidatecount].fromfile = f; 1.465 - candidates[candidatecount].torow = row; 1.466 - candidates[candidatecount].tofile = file; 1.467 - candidatecount++; 1.468 - 1.469 - // capturing move 1.470 - memcpy(&(candidates[candidatecount]), 1.471 - &(candidates[candidatecount-1]), sizeof(Move)); 1.472 - candidates[candidatecount].capture = 1; 1.473 - candidatecount++; 1.474 - } 1.475 - } 1.476 - } 1.477 - 1.478 - if (threatcount) { 1.479 - *threatcount = 0; 1.480 - } 1.481 - 1.482 - 1.483 - _Bool result = 0; 1.484 - 1.485 - for (int i = 0 ; i < candidatecount ; i++) { 1.486 - if (validate_move_rules(gamestate, &(candidates[i])) 1.487 - == VALID_MOVE_SEMANTICS) { 1.488 - result = 1; 1.489 - if (threats && threatcount) { 1.490 - threats[(*threatcount)++] = candidates[i]; 1.491 - } 1.492 - } 1.493 - } 1.494 - 1.495 - return result; 1.496 -} 1.497 - 1.498 -_Bool is_pinned(GameState *gamestate, Move *move) { 1.499 - uint8_t color = move->piece & COLOR_MASK; 1.500 - 1.501 - uint8_t kingfile = 0, kingrow = 0; 1.502 - for (uint8_t row = 0 ; row < 8 ; row++) { 1.503 - for (uint8_t file = 0 ; file < 8 ; file++) { 1.504 - if (gamestate->board[row][file] == (color|KING)) { 1.505 - kingfile = file; 1.506 - kingrow = row; 1.507 - } 1.508 - } 1.509 - } 1.510 - 1.511 - GameState simulation = gamestate_copy_sim(gamestate); 1.512 - Move simmove = *move; 1.513 - apply_move(&simulation, &simmove); 1.514 - _Bool covered = is_covered(&simulation, 1.515 - kingrow, kingfile, opponent_color(color)); 1.516 - gamestate_cleanup(&simulation); 1.517 - 1.518 - return covered; 1.519 -} 1.520 - 1.521 -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, 1.522 - uint8_t color, Move *threats, uint8_t *threatcount) { 1.523 - 1.524 - if (threatcount) { 1.525 - *threatcount = 0; 1.526 - } 1.527 - 1.528 - Move candidates[16]; 1.529 - uint8_t candidatecount; 1.530 - if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { 1.531 - 1.532 - _Bool result = 0; 1.533 - uint8_t kingfile = 0, kingrow = 0; 1.534 - for (uint8_t row = 0 ; row < 8 ; row++) { 1.535 - for (uint8_t file = 0 ; file < 8 ; file++) { 1.536 - if (gamestate->board[row][file] == (color|KING)) { 1.537 - kingfile = file; 1.538 - kingrow = row; 1.539 - } 1.540 - } 1.541 - } 1.542 - 1.543 - for (uint8_t i = 0 ; i < candidatecount ; i++) { 1.544 - GameState simulation = gamestate_copy_sim(gamestate); 1.545 - Move simmove = candidates[i]; 1.546 - apply_move(&simulation, &simmove); 1.547 - if (!is_covered(&simulation, kingrow, kingfile, 1.548 - opponent_color(color))) { 1.549 - result = 1; 1.550 - if (threats && threatcount) { 1.551 - threats[(*threatcount)++] = candidates[i]; 1.552 - } 1.553 - } 1.554 - } 1.555 - 1.556 - return result; 1.557 - } else { 1.558 - return 0; 1.559 - } 1.560 -} 1.561 - 1.562 -static int getlocation(GameState *gamestate, Move *move) { 1.563 - 1.564 - uint8_t color = move->piece & COLOR_MASK; 1.565 - _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; 1.566 - 1.567 - Move threats[16], *threat = NULL; 1.568 - uint8_t threatcount; 1.569 - 1.570 - if (get_threats(gamestate, move->torow, move->tofile, color, 1.571 - threats, &threatcount)) { 1.572 - 1.573 - int reason = INVALID_POSITION; 1.574 - 1.575 - // find threats for the specified position 1.576 - for (uint8_t i = 0 ; i < threatcount ; i++) { 1.577 - if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) 1.578 - == move->piece && 1.579 - (move->fromrow == POS_UNSPECIFIED || 1.580 - move->fromrow == threats[i].fromrow) && 1.581 - (move->fromfile == POS_UNSPECIFIED || 1.582 - move->fromfile == threats[i].fromfile)) { 1.583 - 1.584 - if (threat) { 1.585 - return AMBIGUOUS_MOVE; 1.586 - } else { 1.587 - // found threat is no real threat 1.588 - if (is_pinned(gamestate, &(threats[i]))) { 1.589 - reason = incheck?KING_IN_CHECK:PIECE_PINNED; 1.590 - } else { 1.591 - threat = &(threats[i]); 1.592 - } 1.593 - } 1.594 - } 1.595 - } 1.596 - 1.597 - // can't threaten specified position 1.598 - if (!threat) { 1.599 - return reason; 1.600 - } 1.601 - 1.602 - memcpy(move, threat, sizeof(Move)); 1.603 - return VALID_MOVE_SYNTAX; 1.604 - } else { 1.605 - return INVALID_POSITION; 1.606 - } 1.607 -} 1.608 - 1.609 -int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) { 1.610 - memset(move, 0, sizeof(Move)); 1.611 - move->fromfile = POS_UNSPECIFIED; 1.612 - move->fromrow = POS_UNSPECIFIED; 1.613 - 1.614 - size_t len = strlen(mstr); 1.615 - if (len < 1 || len > 6) { 1.616 - return INVALID_MOVE_SYNTAX; 1.617 - } 1.618 - 1.619 - /* evaluate check/checkmate flags */ 1.620 - if (mstr[len-1] == '+') { 1.621 - len--; mstr[len] = '\0'; 1.622 - move->check = 1; 1.623 - } else if (mstr[len-1] == '#') { 1.624 - len--; mstr[len] = '\0'; 1.625 - /* ignore - validation should set game state */ 1.626 - } 1.627 - 1.628 - /* evaluate promotion */ 1.629 - if (len > 3 && mstr[len-2] == '=') { 1.630 - move->promotion = getpiece(mstr[len-1]); 1.631 - if (!move->promotion) { 1.632 - return INVALID_MOVE_SYNTAX; 1.633 - } else { 1.634 - move->promotion |= color; 1.635 - len -= 2; 1.636 - mstr[len] = 0; 1.637 - } 1.638 - } 1.639 - 1.640 - if (len == 2) { 1.641 - /* pawn move (e.g. "e4") */ 1.642 - move->piece = PAWN; 1.643 - move->tofile = fileidx(mstr[0]); 1.644 - move->torow = rowidx(mstr[1]); 1.645 - } else if (len == 3) { 1.646 - if (strcmp(mstr, "O-O") == 0) { 1.647 - /* king side castling */ 1.648 - move->piece = KING; 1.649 - move->fromfile = fileidx('e'); 1.650 - move->tofile = fileidx('g'); 1.651 - move->fromrow = move->torow = color == WHITE ? 0 : 7; 1.652 - } else { 1.653 - /* move (e.g. "Nf3") */ 1.654 - move->piece = getpiece(mstr[0]); 1.655 - move->tofile = fileidx(mstr[1]); 1.656 - move->torow = rowidx(mstr[2]); 1.657 - } 1.658 - } else if (len == 4) { 1.659 - move->piece = getpiece(mstr[0]); 1.660 - if (!move->piece) { 1.661 - move->piece = PAWN; 1.662 - move->fromfile = fileidx(mstr[0]); 1.663 - } 1.664 - if (mstr[1] == 'x') { 1.665 - /* capture (e.g. "Nxf3", "dxe5") */ 1.666 - move->capture = 1; 1.667 - } else { 1.668 - /* move (e.g. "Ndf3", "N2c3", "e2e4") */ 1.669 - if (isfile(mstr[1])) { 1.670 - move->fromfile = fileidx(mstr[1]); 1.671 - if (move->piece == PAWN) { 1.672 - move->piece = 0; 1.673 - } 1.674 - } else { 1.675 - move->fromrow = rowidx(mstr[1]); 1.676 - } 1.677 - } 1.678 - move->tofile = fileidx(mstr[2]); 1.679 - move->torow = rowidx(mstr[3]); 1.680 - } else if (len == 5) { 1.681 - if (strcmp(mstr, "O-O-O") == 0) { 1.682 - /* queen side castling "O-O-O" */ 1.683 - move->piece = KING; 1.684 - move->fromfile = fileidx('e'); 1.685 - move->tofile = fileidx('c'); 1.686 - move->fromrow = move->torow = color == WHITE ? 0 : 7; 1.687 - } else { 1.688 - move->piece = getpiece(mstr[0]); 1.689 - if (mstr[2] == 'x') { 1.690 - move->capture = 1; 1.691 - if (move->piece) { 1.692 - /* capture (e.g. "Ndxf3") */ 1.693 - move->fromfile = fileidx(mstr[1]); 1.694 - } else { 1.695 - /* long notation capture (e.g. "e5xf6") */ 1.696 - move->piece = PAWN; 1.697 - move->fromfile = fileidx(mstr[0]); 1.698 - move->fromrow = rowidx(mstr[1]); 1.699 - } 1.700 - } else { 1.701 - /* long notation move (e.g. "Nc5a4") */ 1.702 - move->fromfile = fileidx(mstr[1]); 1.703 - move->fromrow = rowidx(mstr[2]); 1.704 - } 1.705 - move->tofile = fileidx(mstr[3]); 1.706 - move->torow = rowidx(mstr[4]); 1.707 - } 1.708 - } else if (len == 6) { 1.709 - /* long notation capture (e.g. "Nc5xf3") */ 1.710 - if (mstr[3] == 'x') { 1.711 - move->capture = 1; 1.712 - move->piece = getpiece(mstr[0]); 1.713 - move->fromfile = fileidx(mstr[1]); 1.714 - move->fromrow = rowidx(mstr[2]); 1.715 - move->tofile = fileidx(mstr[4]); 1.716 - move->torow = rowidx(mstr[5]); 1.717 - } 1.718 - } 1.719 - 1.720 - 1.721 - if (move->piece) { 1.722 - if (move->piece == PAWN 1.723 - && move->torow == (color==WHITE?7:0) 1.724 - && !move->promotion) { 1.725 - return NEED_PROMOTION; 1.726 - } 1.727 - 1.728 - move->piece |= color; 1.729 - if (move->fromfile == POS_UNSPECIFIED 1.730 - || move->fromrow == POS_UNSPECIFIED) { 1.731 - return getlocation(gamestate, move); 1.732 - } else { 1.733 - return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION; 1.734 - } 1.735 - } else { 1.736 - return INVALID_MOVE_SYNTAX; 1.737 - } 1.738 -} 1.739 - 1.740 -_Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, 1.741 - uint8_t color) { 1.742 - 1.743 - Move threats[16]; 1.744 - uint8_t threatcount; 1.745 - if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) { 1.746 - for (int i = 0 ; i < threatcount ; i++) { 1.747 - if (threats[i].piece != (color|KING)) { 1.748 - return 1; 1.749 - } 1.750 - } 1.751 - return 0; 1.752 - } else { 1.753 - return 0; 1.754 - } 1.755 -} 1.756 - 1.757 -uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, 1.758 - uint8_t color) { 1.759 - if (!gameinfo->timecontrol) { 1.760 - return 0; 1.761 - } 1.762 - 1.763 - if (gamestate->movelist) { 1.764 - uint16_t time = gameinfo->time; 1.765 - suseconds_t micros = 0; 1.766 - 1.767 - MoveList *movelist = color == WHITE ? 1.768 - gamestate->movelist : gamestate->movelist->next; 1.769 - 1.770 - while (movelist) { 1.771 - time += gameinfo->addtime; 1.772 - 1.773 - struct movetimeval *movetime = &(movelist->move.movetime); 1.774 - if (movetime->tv_sec >= time) { 1.775 - return 0; 1.776 - } 1.777 - 1.778 - time -= movetime->tv_sec; 1.779 - micros += movetime->tv_usec; 1.780 - 1.781 - movelist = movelist->next ? movelist->next->next : NULL; 1.782 - } 1.783 - 1.784 - time_t sec; 1.785 - movelist = gamestate->lastmove; 1.786 - if ((movelist->move.piece & COLOR_MASK) != color) { 1.787 - struct movetimeval *lastmovetstamp = &(movelist->move.timestamp); 1.788 - struct timeval currenttstamp; 1.789 - gettimeofday(¤ttstamp, NULL); 1.790 - micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec; 1.791 - sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec; 1.792 - if (sec >= time) { 1.793 - return 0; 1.794 - } 1.795 - 1.796 - time -= sec; 1.797 - } 1.798 - 1.799 - sec = micros / 1e6L; 1.800 - 1.801 - if (sec >= time) { 1.802 - return 0; 1.803 - } 1.804 - 1.805 - time -= sec; 1.806 - 1.807 - return time; 1.808 - } else { 1.809 - return gameinfo->time; 1.810 - } 1.811 -}