| 410 Move simmove = *move; |
410 Move simmove = *move; |
| 411 apply_move_impl(&simulation, &simmove, true); |
411 apply_move_impl(&simulation, &simmove, true); |
| 412 |
412 |
| 413 /* find kings for check validation */ |
413 /* find kings for check validation */ |
| 414 uint8_t piececolor = (move->piece & COLOR_MASK); |
414 uint8_t piececolor = (move->piece & COLOR_MASK); |
| |
415 uint8_t oppcolor = opponent_color(piececolor); |
| 415 |
416 |
| 416 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; |
417 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; |
| 417 for (uint8_t row = 0 ; row < 8 ; row++) { |
418 for (uint8_t row = 0 ; row < 8 ; row++) { |
| 418 for (uint8_t file = 0 ; file < 8 ; file++) { |
419 for (uint8_t file = 0 ; file < 8 ; file++) { |
| 419 if (simulation.board[row][file] == |
420 if (simulation.board[row][file] == |
| 427 } |
428 } |
| 428 } |
429 } |
| 429 } |
430 } |
| 430 |
431 |
| 431 /* don't move into or stay in check position */ |
432 /* don't move into or stay in check position */ |
| 432 if (is_covered(&simulation, mykingrow, mykingfile, |
433 if (is_covered(&simulation, mykingrow, mykingfile, oppcolor)) { |
| 433 opponent_color(piececolor))) { |
|
| 434 |
|
| 435 gamestate_cleanup(&simulation); |
434 gamestate_cleanup(&simulation); |
| 436 if ((move->piece & PIECE_MASK) == KING) { |
435 if ((move->piece & PIECE_MASK) == KING) { |
| 437 return KING_MOVES_INTO_CHECK; |
436 return KING_MOVES_INTO_CHECK; |
| 438 } else { |
437 } else { |
| 439 /* last move is always not null in this case */ |
438 /* last move is always not null in this case */ |
| 453 bool canescape = false; |
452 bool canescape = false; |
| 454 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { |
453 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { |
| 455 for (int df = -1 ; df <= 1 && !canescape ; df++) { |
454 for (int df = -1 ; df <= 1 && !canescape ; df++) { |
| 456 if (!(dr == 0 && df == 0) && |
455 if (!(dr == 0 && df == 0) && |
| 457 isidx(opkingrow + dr) && isidx(opkingfile + df)) { |
456 isidx(opkingrow + dr) && isidx(opkingfile + df)) { |
| 458 |
457 /* escape field neither occupied nor covered */ |
| 459 /* escape field neither blocked nor covered */ |
458 canescape = |
| 460 if ((simulation.board[opkingrow + dr][opkingfile + df] |
459 !simulation.board[opkingrow + dr][opkingfile + df] && |
| 461 & COLOR_MASK) != opponent_color(piececolor)) { |
460 !is_covered(&simulation, |
| 462 canescape |= !is_covered(&simulation, |
|
| 463 opkingrow + dr, opkingfile + df, piececolor); |
461 opkingrow + dr, opkingfile + df, piececolor); |
| 464 } |
|
| 465 } |
462 } |
| 466 } |
463 } |
| 467 } |
464 } |
| 468 /* can't escape, can he capture? */ |
465 /* can't escape, can he capture? */ |
| 469 if (!canescape && threatcount == 1) { |
466 if (!canescape && threatcount == 1) { |
| 470 canescape = is_attacked(&simulation, threats[0].fromrow, |
467 /* TODO: this is bugged - we actually need distinguish two cases |
| 471 threats[0].fromfile, opponent_color(piececolor)); |
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); |
| 472 } |
478 } |
| 473 |
479 |
| 474 /* can't capture, can he block? */ |
480 /* can't capture, can he block? */ |
| 475 if (!canescape && threatcount == 1) { |
481 if (!canescape && threatcount == 1) { |
| 476 Move *threat = &(threats[0]); |
482 Move *threat = &(threats[0]); |
| 484 int d = threat->tofile > threat->fromfile ? 1 : -1; |
490 int d = threat->tofile > threat->fromfile ? 1 : -1; |
| 485 uint8_t file = threat->fromfile; |
491 uint8_t file = threat->fromfile; |
| 486 while (!canescape && file != threat->tofile - d) { |
492 while (!canescape && file != threat->tofile - d) { |
| 487 file += d; |
493 file += d; |
| 488 canescape |= is_protected(&simulation, |
494 canescape |= is_protected(&simulation, |
| 489 threat->torow, file, opponent_color(piececolor)); |
495 threat->torow, file, oppcolor); |
| 490 } |
496 } |
| 491 } else if (threat->fromfile == threat->tofile) { |
497 } else if (threat->fromfile == threat->tofile) { |
| 492 /* rook aspect (on file) */ |
498 /* rook aspect (on file) */ |
| 493 int d = threat->torow > threat->fromrow ? 1 : -1; |
499 int d = threat->torow > threat->fromrow ? 1 : -1; |
| 494 uint8_t row = threat->fromrow; |
500 uint8_t row = threat->fromrow; |
| 495 while (!canescape && row != threat->torow - d) { |
501 while (!canescape && row != threat->torow - d) { |
| 496 row += d; |
502 row += d; |
| 497 canescape |= is_protected(&simulation, |
503 canescape |= is_protected(&simulation, |
| 498 row, threat->tofile, opponent_color(piececolor)); |
504 row, threat->tofile, oppcolor); |
| 499 } |
505 } |
| 500 } else { |
506 } else { |
| 501 /* bishop aspect */ |
507 /* bishop aspect */ |
| 502 int dr = threat->torow > threat->fromrow ? 1 : -1; |
508 int dr = threat->torow > threat->fromrow ? 1 : -1; |
| 503 int df = threat->tofile > threat->fromfile ? 1 : -1; |
509 int df = threat->tofile > threat->fromfile ? 1 : -1; |
| 507 while (!canescape && file != threat->tofile - df |
513 while (!canescape && file != threat->tofile - df |
| 508 && row != threat->torow - dr) { |
514 && row != threat->torow - dr) { |
| 509 row += dr; |
515 row += dr; |
| 510 file += df; |
516 file += df; |
| 511 canescape |= is_protected(&simulation, row, file, |
517 canescape |= is_protected(&simulation, row, file, |
| 512 opponent_color(piececolor)); |
518 oppcolor); |
| 513 } |
519 } |
| 514 } |
520 } |
| 515 } |
521 } |
| 516 } |
522 } |
| 517 |
523 |
| 518 if (!canescape) { |
524 if (!canescape) { |
| 519 gamestate->checkmate = 1; |
525 gamestate->checkmate = true; |
| 520 } |
526 } |
| 521 } |
527 } |
| 522 |
528 |
| 523 gamestate_cleanup(&simulation); |
529 gamestate_cleanup(&simulation); |
| 524 |
530 |