From 7ad853f0a3ce1266894a117690711abb92f90c85 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 20 Aug 2019 13:54:01 +0200 Subject: [PATCH] Fix check illegal move checks, added checkmate Checkmate detection is untested. --- assignment1-18/chessboard.c | 78 +++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/assignment1-18/chessboard.c b/assignment1-18/chessboard.c index dfac173..ae8e258 100644 --- a/assignment1-18/chessboard.c +++ b/assignment1-18/chessboard.c @@ -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 }