| 140 size_t ccount; |
140 size_t ccount; |
| 141 if (get_candidates(gamestate, move->torow, move->tofile, |
141 if (get_candidates(gamestate, move->torow, move->tofile, |
| 142 piece_color(move->piece), candidates, &ccount)) { |
142 piece_color(move->piece), candidates, &ccount)) { |
| 143 unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; |
143 unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; |
| 144 for (size_t i = 0 ; i < ccount ; i++) { |
144 for (size_t i = 0 ; i < ccount ; i++) { |
| |
145 // TODO: check if we need to discard pinned pieces here |
| 145 if (candidates[i].piece == move->piece) { |
146 if (candidates[i].piece == move->piece) { |
| 146 ambpiece++; |
147 ambpiece++; |
| 147 if (candidates[i].fromrow == move->fromrow) { |
148 if (candidates[i].fromrow == move->fromrow) { |
| 148 ambrows++; |
149 ambrows++; |
| 149 } |
150 } |
| 546 break; |
547 break; |
| 547 default: |
548 default: |
| 548 return INVALID_MOVE_SYNTAX; |
549 return INVALID_MOVE_SYNTAX; |
| 549 } |
550 } |
| 550 |
551 |
| 551 /* cancel processing to save resources */ |
552 return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED; |
| 552 if (!chkrules) { |
553 } |
| 553 return RULES_VIOLATED; |
554 |
| 554 } |
555 int validate_move(const GameState *gamestate, const Move *move) { |
| 555 |
556 int result = validate_move_rules(gamestate, move); |
| |
557 if (result != VALID_MOVE_SEMANTICS) { |
| |
558 return result; |
| |
559 } |
| |
560 |
| 556 /* test if the move would expose our own king */ |
561 /* test if the move would expose our own king */ |
| 557 GameState simulation = gamestate_copy_sim(gamestate); |
562 GameState simulation = gamestate_copy_sim(gamestate); |
| 558 Move simmove = *move; |
563 Move simmove = *move; |
| 559 apply_move(&simulation, &simmove); |
564 apply_move(&simulation, &simmove); |
| 560 Color piececolor = piece_color(move->piece); |
565 Color piececolor = piece_color(move->piece); |
| 568 kingfile = file; |
573 kingfile = file; |
| 569 kingrow = row; |
574 kingrow = row; |
| 570 } |
575 } |
| 571 } |
576 } |
| 572 } |
577 } |
| 573 int result = VALID_MOVE_SEMANTICS; |
|
| 574 if (is_covered(&simulation, kingrow, kingfile, oppcolor)) { |
578 if (is_covered(&simulation, kingrow, kingfile, oppcolor)) { |
| 575 gamestate_cleanup(&simulation); |
|
| 576 if (piece_type(move->piece) == KING) { |
579 if (piece_type(move->piece) == KING) { |
| 577 result = KING_MOVES_INTO_CHECK; |
580 result = KING_MOVES_INTO_CHECK; |
| 578 } else { |
581 } else { |
| 579 if (is_check_position(gamestate)) { |
582 if (is_check_position(gamestate)) { |
| 580 result = KING_IN_CHECK; |
583 result = KING_IN_CHECK; |
| 583 } |
586 } |
| 584 } |
587 } |
| 585 } |
588 } |
| 586 gamestate_cleanup(&simulation); |
589 gamestate_cleanup(&simulation); |
| 587 |
590 |
| 588 return result; |
|
| 589 } |
|
| 590 |
|
| 591 int validate_move(const GameState *gamestate, const Move *move) { |
|
| 592 int result = validate_move_rules(gamestate, move); |
|
| 593 if (result != VALID_MOVE_SEMANTICS) { |
|
| 594 return result; |
|
| 595 } |
|
| 596 |
|
| 597 /* validate check and checkmate flags */ |
591 /* validate check and checkmate flags */ |
| 598 int cocm = determine_check_or_checkmate(gamestate, move); |
592 int cocm = determine_check_or_checkmate(gamestate, move); |
| 599 if (cocm == 2) { |
593 if (cocm == 2) { |
| 600 if (!move->checkmate) { |
594 if (!move->checkmate) { |
| 601 return MISSING_CHECKMATE; |
595 return MISSING_CHECKMATE; |
| 607 } else if (move->checkmate) { |
601 } else if (move->checkmate) { |
| 608 return INVALID_CHECKMATE; |
602 return INVALID_CHECKMATE; |
| 609 } else if (move->check) { |
603 } else if (move->check) { |
| 610 return INVALID_CHECK; |
604 return INVALID_CHECK; |
| 611 } |
605 } |
| 612 |
|
| 613 |
606 |
| 614 return VALID_MOVE_SEMANTICS; |
607 return VALID_MOVE_SEMANTICS; |
| 615 } |
608 } |
| 616 |
609 |
| 617 Piece piece_at(const GameState *gamestate, Row row, File file) { |
610 Piece piece_at(const GameState *gamestate, Row row, File file) { |
| 673 |
666 |
| 674 bool get_threats(const GameState *gamestate, Row row, File file, |
667 bool get_threats(const GameState *gamestate, Row row, File file, |
| 675 Color color, Move *threats, size_t *threatcount) { |
668 Color color, Move *threats, size_t *threatcount) { |
| 676 |
669 |
| 677 /* simulate a capturing move on the target position */ |
670 /* simulate a capturing move on the target position */ |
| |
671 // TODO: this does NOT disregard the pin, as stated in the spec! |
| 678 Color opcolor = opponent_color(color); |
672 Color opcolor = opponent_color(color); |
| 679 GameState simulation = gamestate_copy_sim(gamestate); |
673 GameState simulation = gamestate_copy_sim(gamestate); |
| 680 if (piece_color(piece_at(&simulation, row, file)) != opcolor) { |
674 if (piece_color(piece_at(&simulation, row, file)) != opcolor) { |
| 681 /* set a fake pawn if the field is not occupied by the opponent */ |
675 /* set a fake pawn if the field is not occupied by the opponent */ |
| 682 piece_set(&simulation, row, file, mkpiece(PAWN, opcolor)); |
676 piece_set(&simulation, row, file, mkpiece(PAWN, opcolor)); |