Fix check illegal move checks, added checkmate
Checkmate detection is untested.
This commit is contained in:
parent
be72018a0a
commit
7ad853f0a3
1 changed files with 66 additions and 12 deletions
|
@ -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) {
|
||||
DEBUG("move: move does not end check state, invalid");
|
||||
return INVALID;
|
||||
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;
|
||||
} else if (player_checks(cb, p)) {
|
||||
if (player_checkmates(cb, p)) {
|
||||
return CHECK_MATE;
|
||||
} else {
|
||||
return CHECK;
|
||||
}
|
||||
// TODO: check checkmate
|
||||
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
|
||||
}
|
||||
|
|
Reference in a new issue