diff -r 4dcfb4c58b6d -r d726e4b46c33 src/chess/rules.c --- a/src/chess/rules.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/rules.c Wed May 28 15:47:57 2014 +0200 @@ -98,19 +98,6 @@ } } -static int getlocation(GameState *gamestate, Move *move) { - uint8_t piece = move->piece & PIECE_MASK; - switch (piece) { - case PAWN: return pawn_getlocation(gamestate, move); - case ROOK: return rook_getlocation(gamestate, move); - case KNIGHT: return knight_getlocation(gamestate, move); - case BISHOP: return bishop_getlocation(gamestate, move); - case QUEEN: return queen_getlocation(gamestate, move); - case KING: return king_getlocation(gamestate, move); - default: return INVALID_MOVE_SYNTAX; - } -} - void apply_move(GameState *gamestate, Move *move) { uint8_t piece = move->piece & PIECE_MASK; uint8_t color = move->piece & COLOR_MASK; @@ -170,13 +157,20 @@ } /* does piece exist */ - if (msrc(gamestate->board, move) != move->piece) { + if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) + != (move->piece&(PIECE_MASK|COLOR_MASK))) { return 0; } /* can't capture own pieces */ if ((mdst(gamestate->board, move) & COLOR_MASK) - == (move->piece & COLOR_MASK)) { + == (move->piece & COLOR_MASK)) { + return 0; + } + + /* 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 0; } @@ -205,6 +199,7 @@ } _Bool validate_move(GameState *gamestate, Move *move) { + // TODO: provide more details via a return code _Bool result = validate_move_rules(gamestate, move); @@ -232,9 +227,9 @@ } /* simulation move for check validation */ - GameState simulation; - memcpy(&simulation, gamestate, sizeof(GameState)); - apply_move(&simulation, move); + GameState simulation = *gamestate; + Move simmove = *move; + apply_move(&simulation, &simmove); /* don't move into or stay in check position */ if (is_covered(&simulation, mykingrow, mykingfile, @@ -323,6 +318,155 @@ return 1; } +_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]))) { + 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; + Move simmove = *move; + apply_move(&simulation, &simmove); + return is_covered(&simulation, kingrow, kingfile, opponent_color(color)); +} + +_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; + 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; + } +} +#include +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)) { + + // 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 { + threat = &(threats[i]); + } + } + } + + // can't threaten specified position + if (!threat) { + return INVALID_POSITION; + } + + // found threat is no real threat + if (is_pinned(gamestate, threat)) { + return incheck?KING_IN_CHECK:PIECE_PINNED; + } else { + memcpy(move, threat, sizeof(Move)); + return VALID_MOVE_SYNTAX; + } + } else { + return INVALID_POSITION; + } +} + int eval_move(GameState *gamestate, char *mstr, Move *move) { memset(move, 0, sizeof(Move)); move->fromfile = POS_UNSPECIFIED; @@ -452,83 +596,6 @@ } } -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - Move candidates[16]; - 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) { - 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++; - } - } - } - - if (threatcount) { - *threatcount = 0; - } - - - _Bool result = 0; - - for (int i = 0 ; i < candidatecount ; i++) { - if (validate_move_rules(gamestate, &(candidates[i]))) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; -} - -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - - Move candidates[16]; - uint8_t candidatecount; - if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { - - if (threatcount) { - *threatcount = 0; - } - _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_MASK) == color) { - kingfile = file; - kingrow = row; - } - } - } - - for (uint8_t i = 0 ; i < candidatecount ; i++) { - GameState simulation; - memcpy(&simulation, gamestate, sizeof(GameState)); - apply_move(&simulation, &(candidates[i])); - if (!is_covered(&simulation, kingrow, kingfile, - opponent_color(color))) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; - } else { - return 0; - } -} - _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, uint8_t color) {