Wed, 11 Jun 2014 15:38:01 +0200
added return code to move validation (for more informative messages) + fixed a bug where simulations added movelist items to the original gamestate
src/chess/rules.c | file | annotate | diff | comparison | revisions | |
src/chess/rules.h | file | annotate | diff | comparison | revisions | |
src/game.c | file | annotate | diff | comparison | revisions | |
src/network.c | file | annotate | diff | comparison | revisions | |
src/network.h | file | annotate | diff | comparison | revisions |
1.1 --- a/src/chess/rules.c Wed May 28 15:47:57 2014 +0200 1.2 +++ b/src/chess/rules.c Wed Jun 11 15:38:01 2014 +0200 1.3 @@ -33,6 +33,17 @@ 1.4 #include <stdlib.h> 1.5 #include <sys/time.h> 1.6 1.7 +static GameState gamestate_copy_sim(GameState *gamestate) { 1.8 + GameState simulation = *gamestate; 1.9 + if (simulation.lastmove) { 1.10 + MoveList *lastmovecopy = malloc(sizeof(MoveList)); 1.11 + *lastmovecopy = *(simulation.lastmove); 1.12 + simulation.movelist = simulation.lastmove = lastmovecopy; 1.13 + } 1.14 + 1.15 + return simulation; 1.16 +} 1.17 + 1.18 void gamestate_cleanup(GameState *gamestate) { 1.19 MoveList *elem; 1.20 elem = gamestate->movelist; 1.21 @@ -145,67 +156,75 @@ 1.22 addmove(gamestate, move); 1.23 } 1.24 1.25 -static _Bool validate_move_rules(GameState *gamestate, Move *move) { 1.26 +static int validate_move_rules(GameState *gamestate, Move *move) { 1.27 /* validate indices (don't trust opponent) */ 1.28 if (!chkidx(move)) { 1.29 - return 0; 1.30 + return INVALID_POSITION; 1.31 } 1.32 1.33 /* must move */ 1.34 if (move->fromfile == move->tofile && move->fromrow == move->torow) { 1.35 - return 0; 1.36 + return INVALID_MOVE_SYNTAX; 1.37 } 1.38 1.39 /* does piece exist */ 1.40 if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) 1.41 != (move->piece&(PIECE_MASK|COLOR_MASK))) { 1.42 - return 0; 1.43 + return INVALID_POSITION; 1.44 } 1.45 1.46 /* can't capture own pieces */ 1.47 if ((mdst(gamestate->board, move) & COLOR_MASK) 1.48 == (move->piece & COLOR_MASK)) { 1.49 - return 0; 1.50 + return RULES_VIOLATED; 1.51 } 1.52 1.53 /* must capture, if and only if destination is occupied */ 1.54 if ((mdst(gamestate->board, move) == 0 && move->capture) || 1.55 (mdst(gamestate->board, move) != 0 && !move->capture)) { 1.56 - return 0; 1.57 + return INVALID_MOVE_SYNTAX; 1.58 } 1.59 1.60 /* validate individual rules */ 1.61 + _Bool chkrules; 1.62 switch (move->piece & PIECE_MASK) { 1.63 case PAWN: 1.64 - return pawn_chkrules(gamestate, move) && 1.65 + chkrules = pawn_chkrules(gamestate, move) && 1.66 !pawn_isblocked(gamestate, move); 1.67 + break; 1.68 case ROOK: 1.69 - return rook_chkrules(move) && 1.70 + chkrules = rook_chkrules(move) && 1.71 !rook_isblocked(gamestate, move); 1.72 + break; 1.73 case KNIGHT: 1.74 - return knight_chkrules(move); /* knight is never blocked */ 1.75 + chkrules = knight_chkrules(move); /* knight is never blocked */ 1.76 + break; 1.77 case BISHOP: 1.78 - return bishop_chkrules(move) && 1.79 + chkrules = bishop_chkrules(move) && 1.80 !bishop_isblocked(gamestate, move); 1.81 + break; 1.82 case QUEEN: 1.83 - return queen_chkrules(move) && 1.84 + chkrules = queen_chkrules(move) && 1.85 !queen_isblocked(gamestate, move); 1.86 + break; 1.87 case KING: 1.88 - return king_chkrules(gamestate, move) && 1.89 + chkrules = king_chkrules(gamestate, move) && 1.90 !king_isblocked(gamestate, move); 1.91 + break; 1.92 default: 1.93 - return 0; 1.94 + return INVALID_MOVE_SYNTAX; 1.95 } 1.96 + 1.97 + return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED; 1.98 } 1.99 1.100 -_Bool validate_move(GameState *gamestate, Move *move) { 1.101 - // TODO: provide more details via a return code 1.102 +int validate_move(GameState *gamestate, Move *move) { 1.103 1.104 - _Bool result = validate_move_rules(gamestate, move); 1.105 + int result = validate_move_rules(gamestate, move); 1.106 1.107 /* cancel processing to save resources */ 1.108 - if (!result) { 1.109 - return 0; 1.110 + if (result != VALID_MOVE_SEMANTICS) { 1.111 + return result; 1.112 } 1.113 1.114 /* find kings for check validation */ 1.115 @@ -226,15 +245,23 @@ 1.116 } 1.117 } 1.118 1.119 - /* simulation move for check validation */ 1.120 - GameState simulation = *gamestate; 1.121 + /* simulate move for check validation */ 1.122 + GameState simulation = gamestate_copy_sim(gamestate); 1.123 Move simmove = *move; 1.124 apply_move(&simulation, &simmove); 1.125 1.126 /* don't move into or stay in check position */ 1.127 if (is_covered(&simulation, mykingrow, mykingfile, 1.128 opponent_color(piececolor))) { 1.129 - return 0; 1.130 + 1.131 + gamestate_cleanup(&simulation); 1.132 + if ((move->piece & PIECE_MASK) == KING) { 1.133 + return KING_MOVES_INTO_CHECK; 1.134 + } else { 1.135 + /* last move is always not null in this case */ 1.136 + return gamestate->lastmove->move.check ? 1.137 + KING_IN_CHECK : PIECE_PINNED; 1.138 + } 1.139 } 1.140 1.141 /* correct check and checkmate flags (move is still valid) */ 1.142 @@ -315,7 +342,9 @@ 1.143 } 1.144 } 1.145 1.146 - return 1; 1.147 + gamestate_cleanup(&simulation); 1.148 + 1.149 + return VALID_MOVE_SEMANTICS; 1.150 } 1.151 1.152 _Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, 1.153 @@ -351,7 +380,8 @@ 1.154 _Bool result = 0; 1.155 1.156 for (int i = 0 ; i < candidatecount ; i++) { 1.157 - if (validate_move_rules(gamestate, &(candidates[i]))) { 1.158 + if (validate_move_rules(gamestate, &(candidates[i])) 1.159 + == VALID_MOVE_SEMANTICS) { 1.160 result = 1; 1.161 if (threats && threatcount) { 1.162 threats[(*threatcount)++] = candidates[i]; 1.163 @@ -375,10 +405,14 @@ 1.164 } 1.165 } 1.166 1.167 - GameState simulation = *gamestate; 1.168 + GameState simulation = gamestate_copy_sim(gamestate); 1.169 Move simmove = *move; 1.170 apply_move(&simulation, &simmove); 1.171 - return is_covered(&simulation, kingrow, kingfile, opponent_color(color)); 1.172 + _Bool covered = is_covered(&simulation, 1.173 + kingrow, kingfile, opponent_color(color)); 1.174 + gamestate_cleanup(&simulation); 1.175 + 1.176 + return covered; 1.177 } 1.178 1.179 _Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, 1.180 @@ -404,7 +438,7 @@ 1.181 } 1.182 1.183 for (uint8_t i = 0 ; i < candidatecount ; i++) { 1.184 - GameState simulation = *gamestate; 1.185 + GameState simulation = gamestate_copy_sim(gamestate); 1.186 Move simmove = candidates[i]; 1.187 apply_move(&simulation, &simmove); 1.188 if (!is_covered(&simulation, kingrow, kingfile, 1.189 @@ -414,6 +448,7 @@ 1.190 threats[(*threatcount)++] = candidates[i]; 1.191 } 1.192 } 1.193 + gamestate_cleanup(&simulation); 1.194 } 1.195 1.196 return result; 1.197 @@ -421,7 +456,7 @@ 1.198 return 0; 1.199 } 1.200 } 1.201 -#include <ncurses.h> 1.202 + 1.203 static int getlocation(GameState *gamestate, Move *move) { 1.204 1.205 uint8_t color = move->piece & COLOR_MASK; 1.206 @@ -473,6 +508,9 @@ 1.207 move->fromrow = POS_UNSPECIFIED; 1.208 1.209 size_t len = strlen(mstr); 1.210 + if (len < 1 || len > 6) { 1.211 + return INVALID_MOVE_SYNTAX; 1.212 + } 1.213 1.214 /* evaluate check/checkmate flags */ 1.215 if (mstr[len-1] == '+') { 1.216 @@ -513,7 +551,6 @@ 1.217 move->tofile = fileidx(mstr[1]); 1.218 move->torow = rowidx(mstr[2]); 1.219 } 1.220 - 1.221 } else if (len == 4) { 1.222 move->piece = getpiece(mstr[0]); 1.223 if (!move->piece) {
2.1 --- a/src/chess/rules.h Wed May 28 15:47:57 2014 +0200 2.2 +++ b/src/chess/rules.h Wed Jun 11 15:38:01 2014 +0200 2.3 @@ -33,13 +33,16 @@ 2.4 #include <stdint.h> 2.5 #include <sys/time.h> 2.6 2.7 -#define VALID_MOVE_SYNTAX 0 2.8 -#define INVALID_MOVE_SYNTAX 1 2.9 -#define INVALID_POSITION 2 2.10 -#define AMBIGUOUS_MOVE 3 2.11 -#define NEED_PROMOTION 4 2.12 -#define PIECE_PINNED 5 2.13 -#define KING_IN_CHECK 6 2.14 +#define VALID_MOVE_SYNTAX 0 2.15 +#define VALID_MOVE_SEMANTICS 0 /* use same code for a success */ 2.16 +#define INVALID_MOVE_SYNTAX 1 2.17 +#define INVALID_POSITION 2 2.18 +#define AMBIGUOUS_MOVE 3 2.19 +#define NEED_PROMOTION 4 2.20 +#define PIECE_PINNED 5 2.21 +#define KING_IN_CHECK 6 2.22 +#define KING_MOVES_INTO_CHECK 7 2.23 +#define RULES_VIOLATED 10 2.24 2.25 2.26 #define PIECE_MASK 0x0F 2.27 @@ -268,7 +271,7 @@ 2.28 * @param gamestate the current game state 2.29 * @param mstr the input string to parse 2.30 * @param move a pointer to object where the move data shall be stored 2.31 - * @return status code (see rules/rules.h for the list of codes) 2.32 + * @return status code (see macros in this file for the list of codes) 2.33 */ 2.34 int eval_move(GameState *gamestate, char *mstr, Move *move); 2.35 2.36 @@ -276,9 +279,9 @@ 2.37 * Validates move by applying chess rules. 2.38 * @param gamestate the current game state 2.39 * @param move the move to validate 2.40 - * @return TRUE, if the move complies to chess rules, FALSE otherwise 2.41 + * @return status code (see macros in this file for the list of codes) 2.42 */ 2.43 -_Bool validate_move(GameState *gamestate, Move *move); 2.44 +int validate_move(GameState *gamestate, Move *move); 2.45 2.46 /** 2.47 * Applies a move and deletes captured pieces.
3.1 --- a/src/game.c Wed May 28 15:47:57 2014 +0200 3.2 +++ b/src/game.c Wed Jun 11 15:38:01 2014 +0200 3.3 @@ -162,7 +162,7 @@ 3.4 printw("Ambiguous move - please specify the piece to move."); 3.5 break; 3.6 case INVALID_POSITION: 3.7 - printw("Cannot find the piece that shall be moved."); 3.8 + printw("No piece can be moved this way."); 3.9 break; 3.10 case NEED_PROMOTION: 3.11 printw("You need to promote the pawn (append \"=Q\" e.g.)!"); 3.12 @@ -176,6 +176,12 @@ 3.13 case INVALID_MOVE_SYNTAX: 3.14 printw("Can't interpret move - please use algebraic notation."); 3.15 break; 3.16 + case RULES_VIOLATED: 3.17 + printw("Move does not comply chess rules."); 3.18 + break; 3.19 + case KING_MOVES_INTO_CHECK: 3.20 + printw("Can't move the king into a check position."); 3.21 + break; 3.22 default: 3.23 printw("Unknown move parser error."); 3.24 } 3.25 @@ -218,7 +224,8 @@ 3.26 int eval_result = eval_move(gamestate, movestr, &move); 3.27 switch (eval_result) { 3.28 case VALID_MOVE_SYNTAX: 3.29 - if (validate_move(gamestate, &move)) { 3.30 + eval_result = validate_move(gamestate, &move); 3.31 + if (eval_result == VALID_MOVE_SEMANTICS) { 3.32 apply_move(gamestate, &move); 3.33 if (gamestate->checkmate) { 3.34 printw("Checkmate!"); 3.35 @@ -232,7 +239,7 @@ 3.36 return 0; 3.37 } 3.38 } else { 3.39 - printw("Invalid move."); 3.40 + eval_move_failed_msg(eval_result); 3.41 } 3.42 break; 3.43 default: 3.44 @@ -306,11 +313,15 @@ 3.45 case VALID_MOVE_SYNTAX: 3.46 net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); 3.47 code = net_recieve_code(opponent); 3.48 - move.check = code == NETCODE_CHECK; 3.49 + move.check = code == NETCODE_CHECK || 3.50 + code == NETCODE_CHECKMATE; 3.51 gamestate->checkmate = code == NETCODE_CHECKMATE; 3.52 gamestate->stalemate = code == NETCODE_STALEMATE; 3.53 if (code == NETCODE_DECLINE) { 3.54 - printw("Invalid move."); 3.55 + uint32_t reason; 3.56 + net_recieve_data(opponent, &reason, sizeof(uint32_t)); 3.57 + reason = ntohl(reason); 3.58 + eval_move_failed_msg(reason); 3.59 } else if (code == NETCODE_ACCEPT 3.60 || code == NETCODE_CHECK 3.61 || code == NETCODE_CHECKMATE 3.62 @@ -397,7 +408,8 @@ 3.63 break; 3.64 case NETCODE_MOVE: 3.65 net_recieve_data(opponent, &move, sizeof(Move)); 3.66 - if (validate_move(gamestate, &move)) { 3.67 + code = validate_move(gamestate, &move); 3.68 + if (code == VALID_MOVE_SEMANTICS) { 3.69 apply_move(gamestate, &move); 3.70 if (move.check) { 3.71 net_send_code(opponent, NETCODE_CHECK); 3.72 @@ -416,7 +428,9 @@ 3.73 } 3.74 return 0; 3.75 } else { 3.76 - net_send_code(opponent, NETCODE_DECLINE); 3.77 + uint32_t reason = htonl(code); 3.78 + net_send_data(opponent, NETCODE_DECLINE, 3.79 + &reason, sizeof(uint32_t)); 3.80 } 3.81 break; 3.82 default:
4.1 --- a/src/network.c Wed May 28 15:47:57 2014 +0200 4.2 +++ b/src/network.c Wed Jun 11 15:38:01 2014 +0200 4.3 @@ -56,7 +56,7 @@ 4.4 } 4.5 } 4.6 4.7 -int getaddrinfo_intrnl(char *host, char *port, struct addrinfo **info) { 4.8 +static int getaddrinfo_intrnl(char *host, char *port, struct addrinfo **info) { 4.9 struct addrinfo hints; 4.10 memset(&hints, 0, sizeof(hints)); 4.11 hints.ai_socktype = SOCK_STREAM;
5.1 --- a/src/network.h Wed May 28 15:47:57 2014 +0200 5.2 +++ b/src/network.h Wed Jun 11 15:38:01 2014 +0200 5.3 @@ -49,7 +49,7 @@ 5.4 #define NETCODE_TIMEOVER 0x44 5.5 #define NETCODE_CONNLOST 0x80 5.6 5.7 -#define NETCODE_VERSION 13 5.8 +#define NETCODE_VERSION 14 5.9 5.10 typedef struct { 5.11 int fd; /* -1, if we are the client */