src/chess/rules.c

changeset 28
0c1371488d87
parent 27
efeb98bc69c9
child 29
c6a1ad6cf749
equal deleted inserted replaced
27:efeb98bc69c9 28:0c1371488d87
88 case KING: return king_getlocation(gamestate, move); 88 case KING: return king_getlocation(gamestate, move);
89 default: return INVALID_MOVE_SYNTAX; 89 default: return INVALID_MOVE_SYNTAX;
90 } 90 }
91 } 91 }
92 92
93 _Bool is_covered(GameState *gamestate,uint8_t row,uint8_t file,uint8_t color) { 93 _Bool get_any_threat_for(GameState *gamestate, uint8_t row, uint8_t file,
94 uint8_t color, Move *threat) {
94 Move threats[16]; 95 Move threats[16];
95 int threatcount = 0; 96 int threatcount = 0;
96 for (uint8_t r = 0 ; r < 8 ; r++) { 97 for (uint8_t r = 0 ; r < 8 ; r++) {
97 for (uint8_t f = 0 ; f < 8 ; f++) { 98 for (uint8_t f = 0 ; f < 8 ; f++) {
98 if ((gamestate->board[r][f] & COLOR_MASK) == color) { 99 if ((gamestate->board[r][f] & COLOR_MASK) == color) {
100 memset(&(threats[threatcount]), 0, sizeof(Move));
99 threats[threatcount].piece = gamestate->board[r][f]; 101 threats[threatcount].piece = gamestate->board[r][f];
100 threats[threatcount].fromrow = r; 102 threats[threatcount].fromrow = r;
101 threats[threatcount].fromfile = f; 103 threats[threatcount].fromfile = f;
102 threats[threatcount].torow = row; 104 threats[threatcount].torow = row;
103 threats[threatcount].tofile = file; 105 threats[threatcount].tofile = file;
106 } 108 }
107 } 109 }
108 110
109 for (int i = 0 ; i < threatcount ; i++) { 111 for (int i = 0 ; i < threatcount ; i++) {
110 if (validate_move(gamestate, &(threats[i]))) { 112 if (validate_move(gamestate, &(threats[i]))) {
113 if (threat) {
114 *threat = threats[i];
115 }
111 return 1; 116 return 1;
112 } 117 }
113 } 118 }
114 119
115 return 0; 120 return 0;
156 } else if (move->tofile == fileidx('c')) { 161 } else if (move->tofile == fileidx('c')) {
157 gamestate->board[move->torow][fileidx('a')] = 0; 162 gamestate->board[move->torow][fileidx('a')] = 0;
158 gamestate->board[move->torow][fileidx('d')] = color|ROOK; 163 gamestate->board[move->torow][fileidx('d')] = color|ROOK;
159 } 164 }
160 } 165 }
161 166
162 addmove(gamestate, move); 167 addmove(gamestate, move);
163 } 168 }
164 169
165 _Bool validate_move(GameState *gamestate, Move *move) { 170 _Bool validate_move(GameState *gamestate, Move *move) {
166 _Bool result; 171 _Bool result;
177 182
178 /* does piece exist */ 183 /* does piece exist */
179 result = msrc(gamestate->board, move) == move->piece; 184 result = msrc(gamestate->board, move) == move->piece;
180 185
181 /* can't capture own pieces */ 186 /* can't capture own pieces */
182 if ((mdst(gamestate->board, move) & COLOR_MASK) 187 uint8_t piececolor = (move->piece & COLOR_MASK);
183 == (move->piece & COLOR_MASK)) { 188 if ((mdst(gamestate->board, move) & COLOR_MASK) == piececolor) {
184 return 0; 189 return 0;
185 } 190 }
186 191
187 /* validate individual rules */ 192 /* validate individual rules */
188 switch (move->piece & PIECE_MASK) { 193 switch (move->piece & PIECE_MASK) {
217 /* cancel processing to avoid recursion overflow with is_covered() */ 222 /* cancel processing to avoid recursion overflow with is_covered() */
218 if (!result) { 223 if (!result) {
219 return 0; 224 return 0;
220 } 225 }
221 226
222 /* is piece pinned */ 227 /* find kings for check validation */
223 // TODO: make it so 228 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0;
229 for (uint8_t row = 0 ; row < 8 ; row++) {
230 for (uint8_t file = 0 ; file < 8 ; file++) {
231 if (gamestate->board[row][file] ==
232 (piececolor == WHITE?WKING:BKING)) {
233 mykingfile = file;
234 mykingrow = row;
235 } else if (gamestate->board[row][file] ==
236 (piececolor == WHITE?BKING:WKING)) {
237 opkingfile = file;
238 opkingrow = row;
239 }
240 }
241 }
242
243 /* simulation move for check validation */
244 GameState simulation;
245 memcpy(&simulation, gamestate, sizeof(GameState));
246 apply_move(&simulation, move);
247
248 /* don't move into or stay in check position */
249 if (is_covered(&simulation, mykingrow, mykingfile,
250 opponent_color(piececolor))) {
251 return 0;
252 }
224 253
225 /* correct check and checkmate flags (move is still valid) */ 254 /* correct check and checkmate flags (move is still valid) */
226 // TODO: make it so 255 Move threat;
227 256 move->check = get_any_threat_for(&simulation, opkingrow, opkingfile,
228 return result; 257 piececolor, &threat);
258
259 if (move->check) {
260 /* determine possible escape fields */
261 _Bool canescape = 0;
262 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
263 for (int df = -1 ; df <= 1 && !canescape ; df++) {
264 if (!(dr == 0 && df == 0) &&
265 isidx(opkingrow + dr) && isidx(opkingfile + df)) {
266
267 /* escape field neither blocked nor covered */
268 if ((simulation.board[opkingrow + dr][opkingfile + df]
269 & COLOR_MASK) != opponent_color(piececolor)) {
270 canescape |= !is_covered(&simulation,
271 opkingrow + dr, opkingfile + df, piececolor);
272 }
273 }
274 }
275 }
276 /* can't escape, can we capture? */
277 if (!canescape) {
278 canescape = is_covered(&simulation, threat.fromrow,
279 threat.fromfile, opponent_color(piececolor));
280
281 /* can't capture, can we block? */
282 // TODO: make it so
283
284 if (!canescape) {
285 gamestate->checkmate = 1;
286 }
287 }
288 }
289
290 return 1;
229 } 291 }
230 292
231 int eval_move(GameState *gamestate, char *mstr, Move *move) { 293 int eval_move(GameState *gamestate, char *mstr, Move *move) {
232 memset(move, 0, sizeof(Move)); 294 memset(move, 0, sizeof(Move));
233 move->fromfile = POS_UNSPECIFIED; 295 move->fromfile = POS_UNSPECIFIED;

mercurial