--- a/src/chess/rules.c Thu Apr 03 16:07:04 2014 +0200 +++ b/src/chess/rules.c Fri Apr 04 17:36:42 2014 +0200 @@ -90,12 +90,14 @@ } } -_Bool is_covered(GameState *gamestate,uint8_t row,uint8_t file,uint8_t color) { +_Bool get_any_threat_for(GameState *gamestate, uint8_t row, uint8_t file, + uint8_t color, Move *threat) { Move threats[16]; int threatcount = 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(&(threats[threatcount]), 0, sizeof(Move)); threats[threatcount].piece = gamestate->board[r][f]; threats[threatcount].fromrow = r; threats[threatcount].fromfile = f; @@ -108,6 +110,9 @@ for (int i = 0 ; i < threatcount ; i++) { if (validate_move(gamestate, &(threats[i]))) { + if (threat) { + *threat = threats[i]; + } return 1; } } @@ -158,7 +163,7 @@ gamestate->board[move->torow][fileidx('d')] = color|ROOK; } } - + addmove(gamestate, move); } @@ -179,8 +184,8 @@ result = msrc(gamestate->board, move) == move->piece; /* can't capture own pieces */ - if ((mdst(gamestate->board, move) & COLOR_MASK) - == (move->piece & COLOR_MASK)) { + uint8_t piececolor = (move->piece & COLOR_MASK); + if ((mdst(gamestate->board, move) & COLOR_MASK) == piececolor) { return 0; } @@ -219,13 +224,70 @@ return 0; } - /* is piece pinned */ - // TODO: make it so + /* find kings for check validation */ + 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; + } + } + } + + /* simulation move for check validation */ + GameState simulation; + memcpy(&simulation, gamestate, sizeof(GameState)); + apply_move(&simulation, move); + + /* don't move into or stay in check position */ + if (is_covered(&simulation, mykingrow, mykingfile, + opponent_color(piececolor))) { + return 0; + } /* correct check and checkmate flags (move is still valid) */ - // TODO: make it so + Move threat; + move->check = get_any_threat_for(&simulation, opkingrow, opkingfile, + piececolor, &threat); - return result; + 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 we capture? */ + if (!canescape) { + canescape = is_covered(&simulation, threat.fromrow, + threat.fromfile, opponent_color(piececolor)); + + /* can't capture, can we block? */ + // TODO: make it so + + if (!canescape) { + gamestate->checkmate = 1; + } + } + } + + return 1; } int eval_move(GameState *gamestate, char *mstr, Move *move) {