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