Fix check illegal move checks, added checkmate

Checkmate detection is untested.
This commit is contained in:
Claudio Maggioni (maggicl) 2019-08-20 13:54:01 +02:00
parent be72018a0a
commit 7ad853f0a3

View file

@ -13,8 +13,10 @@
#define DEBUG(...) (void) 0; #define DEBUG(...) (void) 0;
#endif #endif
static inline void cb_move(struct chessboard* cb, static inline enum pieces cb_move(struct chessboard* cb,
int from_row, int from_col, int to_row, int to_col); int from_row, int from_col, int to_row, int to_col);
static inline void cb_move_restore(struct chessboard* cb, enum pieces piece,
int ex_from_row, int ex_from_col, int ex_to_row, int ex_to_col);
static inline int sign(int n); static inline int sign(int n);
static inline enum player player(struct chessboard* cb, int row, int col); static inline enum player player(struct chessboard* cb, int row, int col);
static inline bool is_empty(struct chessboard* cb, int row, int col); static inline bool is_empty(struct chessboard* cb, int row, int col);
@ -93,10 +95,19 @@ void print_chessboard(struct chessboard * cb) {
} }
inline void cb_move(struct chessboard* cb, inline enum pieces cb_move(struct chessboard* cb,
int from_row, int from_col, int to_row, int to_col) { int from_row, int from_col, int to_row, int to_col) {
enum pieces tmp = cb->position[to_row][to_col];
cb->position[to_row][to_col] = cb->position[from_row][from_col]; cb->position[to_row][to_col] = cb->position[from_row][from_col];
cb->position[from_row][from_col] = EMPTY; cb->position[from_row][from_col] = EMPTY;
return tmp;
}
inline void cb_move_restore(struct chessboard* cb, enum pieces piece,
int ex_from_row, int ex_from_col, int ex_to_row, int ex_to_col) {
cb->position[ex_from_row][ex_from_col] =
cb->position[ex_to_row][ex_to_col];
cb->position[ex_to_row][ex_to_col] = piece;
} }
inline bool is_empty(struct chessboard* cb, int row, int col) { inline bool is_empty(struct chessboard* cb, int row, int col) {
@ -285,6 +296,44 @@ bool player_checks(struct chessboard *cb, enum player p) {
return false; return false;
} }
bool player_checkmates(struct chessboard *cb, enum player p) {
int i, j;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
if (is_empty(cb, i, j) || player(cb, i, j) == p) {
continue;
}
int k, l;
for (k = 0; k < 8; k++) {
for (l = 0; l < 8; l++) {
if ((k == i && l == j) ||
is_empty(cb, k, l) ||
player(cb, k, l) != p) {
continue;
}
bool can = can_move(cb, p == BLACK ? WHITE : BLACK,
i, j, k, l);
if (!can) {
continue;
}
enum pieces tmp = cb_move(cb, i, j, k, l);
bool check = player_checks(cb, p);
cb_move_restore(cb, tmp, i, j, k, l);
if (!check) {
return false;
}
}
}
}
}
return true;
}
enum mstatus move( enum mstatus move(
struct chessboard * cb, enum player p, struct chessboard * cb, enum player p,
const char * from, const char * to) { const char * from, const char * to) {
@ -331,21 +380,24 @@ enum mstatus move(
return INVALID; return INVALID;
} }
bool check_before_move = player_checks(cb, p == WHITE ? BLACK : WHITE); bool check_before = player_checks(cb, p == WHITE ? BLACK : WHITE);
bool can = can_move(cb, p, from_row, from_col, to_row, to_col); bool can = can_move(cb, p, from_row, from_col, to_row, to_col);
if (!can) { if (!can) {
return INVALID; return INVALID;
} else { } else {
// FIXME: check if move is allowed in check state // FIXME: check if move is allowed in check state
cb_move(cb, from_row, from_col, to_row, to_col); enum pieces tmp = cb_move(cb, from_row, from_col, to_row, to_col);
if (player_checks(cb, p)) { if (player_checks(cb, p == WHITE ? BLACK : WHITE) && check_before) {
if (check_before_move) { DEBUG("move: move does not end check state, invalid");
DEBUG("move: move does not end check state, invalid"); cb_move_restore(cb, tmp, from_row, from_col, to_row, to_col);
return INVALID; return INVALID;
} else if (player_checks(cb, p)) {
if (player_checkmates(cb, p)) {
return CHECK_MATE;
} else {
return CHECK;
} }
// TODO: check checkmate
return CHECK;
} else { } else {
return VALID; return VALID;
} }
@ -357,18 +409,19 @@ int main() {
init_chessboard(&cb); init_chessboard(&cb);
enum player p = WHITE; enum player p = WHITE;
char from[5], to[5]; char from[5], to[5];
from[0] = '\0'; while (true) {
while(1) {
print_chessboard(&cb); print_chessboard(&cb);
printf("%s moves.\n", p == WHITE ? "White" : "Black"); printf("%s moves.\n", p == WHITE ? "White" : "Black");
printf("From: "); printf("From: ");
fgets(from, 5, stdin); fgets(from, 5, stdin);
// remove trailing \n: https://stackoverflow.com/q/2693776 // remove trailing \n: https://stackoverflow.com/q/2693776
strtok(from, "\n"); strtok(from, "\n");
if (strcmp(from, "exit") == 0) { if (strcmp(from, "exit") == 0) {
printf("Exiting...\n"); printf("Exiting...\n");
return 0; return 0;
} }
printf("To: "); printf("To: ");
fgets(to, 5, stdin); fgets(to, 5, stdin);
strtok(to, "\n"); strtok(to, "\n");
@ -386,6 +439,7 @@ int main() {
case CHECK_MATE: case CHECK_MATE:
printf("Checkmate, %s wins.\n", p == WHITE ? "white" : "black"); printf("Checkmate, %s wins.\n", p == WHITE ? "white" : "black");
} }
if (s != INVALID) { if (s != INVALID) {
p = !p; // switch player: this works since WHITE = 0 and BLACK = 1 p = !p; // switch player: this works since WHITE = 0 and BLACK = 1
} }