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) {