src/chess/rules.c

changeset 139
fa10bee331ac
parent 137
43d1b3c33369
equal deleted inserted replaced
138:bcd6100373ef 139:fa10bee331ac
262 case 'K': return KING; 262 case 'K': return KING;
263 default: return 0; 263 default: return 0;
264 } 264 }
265 } 265 }
266 266
267 // TODO: check if we really need this "simulate" flag for performance
267 static void apply_move_impl(GameState *gamestate, Move *move, bool simulate) { 268 static void apply_move_impl(GameState *gamestate, Move *move, bool simulate) {
268 /* format move before moving (s.t. ambiguities can be resolved) */ 269 /* format move before moving (s.t. ambiguities can be resolved) */
269 if (!simulate) { 270 if (!simulate) {
270 if (!move->string[0]) { 271 if (!move->string[0]) {
271 format_move(gamestate, move); 272 format_move(gamestate, move);
450 if (move->check) { 451 if (move->check) {
451 /* determine possible escape fields */ 452 /* determine possible escape fields */
452 bool canescape = false; 453 bool canescape = false;
453 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { 454 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
454 for (int df = -1 ; df <= 1 && !canescape ; df++) { 455 for (int df = -1 ; df <= 1 && !canescape ; df++) {
455 if (!(dr == 0 && df == 0) && 456 if (dr == 0 && df == 0) continue;
456 isidx(opkingrow + dr) && isidx(opkingfile + df)) { 457 if (!isidx(opkingrow + dr)) continue;
457 /* escape field neither occupied nor covered */ 458 if (!isidx(opkingfile + df)) continue;
458 canescape = 459 uint8_t er = opkingrow + dr;
459 !simulation.board[opkingrow + dr][opkingfile + df] && 460 uint8_t ef = opkingfile + df;
460 !is_covered(&simulation, 461
461 opkingrow + dr, opkingfile + df, piececolor); 462 /* check if escape field is already covered (threatened) */
463 if (is_covered(&simulation, er, ef, piececolor))
464 continue;
465
466 /* check if piece of the king's color blocks the field */
467 if ((simulation.board[er][ef] & COLOR_MASK) == oppcolor)
468 continue;
469
470 /* check if an attacking piece blocks the field */
471 if ((simulation.board[er][ef] & COLOR_MASK) == piececolor) {
472 /* test if the king can fight back */
473 GameState sim_retaliate = gamestate_copy_sim(&simulation);
474 Move move_retaliate = {0};
475 move_retaliate.piece = (oppcolor|KING);
476 move_retaliate.fromrow = opkingrow;
477 move_retaliate.fromfile = opkingfile;
478 move_retaliate.torow = er;
479 move_retaliate.tofile = ef;
480 move_retaliate.capture = 1;
481 apply_move_impl(&sim_retaliate, &move_retaliate, true);
482 canescape = !is_covered(&sim_retaliate, er, ef, piececolor);
483 gamestate_cleanup(&sim_retaliate);
484 } else {
485 /* the field is not covered and unoccupied */
486 canescape = true;
462 } 487 }
463 } 488 }
464 } 489 }
465 /* can't escape, can he capture? */ 490
491 /* can't escape, can the king be rescued? */
466 if (!canescape && threatcount == 1) { 492 if (!canescape && threatcount == 1) {
467 /* TODO: this is bugged - we actually need distinguish two cases 493 canescape = is_protected(&simulation,
468 * 1. another piece can rescue the king
469 * (this is what is implemented now)
470 * 2. the king can kill the attacker
471 * - in this case, the threatcount is irrelevant, because
472 * the king moves out of the current threat
473 * - we must verify that the king can actually kill the
474 * attacker without running into a new check
475 */
476 canescape = is_attacked(&simulation,
477 threats[0].fromrow, threats[0].fromfile, oppcolor); 494 threats[0].fromrow, threats[0].fromfile, oppcolor);
478 } 495 }
479 496
480 /* can't capture, can he block? */ 497 /* can't capture, can he block? */
481 if (!canescape && threatcount == 1) { 498 if (!canescape && threatcount == 1) {

mercurial