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;
|
#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
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue