205 case 'K': return KING; |
205 case 'K': return KING; |
206 default: return 0; |
206 default: return 0; |
207 } |
207 } |
208 } |
208 } |
209 |
209 |
210 static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) { |
210 static void apply_move_impl(GameState *gamestate, Move *move, bool simulate) { |
211 /* format move before moving (s.t. ambiguities can be resolved) */ |
211 /* format move before moving (s.t. ambiguities can be resolved) */ |
212 if (!simulate) { |
212 if (!simulate) { |
213 if (!move->string[0]) { |
213 if (!move->string[0]) { |
214 format_move(gamestate, move); |
214 format_move(gamestate, move); |
215 } |
215 } |
292 (mdst(gamestate->board, move) != 0 && !move->capture)) { |
292 (mdst(gamestate->board, move) != 0 && !move->capture)) { |
293 return INVALID_MOVE_SYNTAX; |
293 return INVALID_MOVE_SYNTAX; |
294 } |
294 } |
295 |
295 |
296 /* validate individual rules */ |
296 /* validate individual rules */ |
297 _Bool chkrules; |
297 bool chkrules; |
298 switch (move->piece & PIECE_MASK) { |
298 switch (move->piece & PIECE_MASK) { |
299 case PAWN: |
299 case PAWN: |
300 chkrules = pawn_chkrules(gamestate, move) && |
300 chkrules = pawn_chkrules(gamestate, move) && |
301 !pawn_isblocked(gamestate, move); |
301 !pawn_isblocked(gamestate, move); |
302 break; |
302 break; |
378 move->check = get_threats(&simulation, opkingrow, opkingfile, |
378 move->check = get_threats(&simulation, opkingrow, opkingfile, |
379 piececolor, threats, &threatcount); |
379 piececolor, threats, &threatcount); |
380 |
380 |
381 if (move->check) { |
381 if (move->check) { |
382 /* determine possible escape fields */ |
382 /* determine possible escape fields */ |
383 _Bool canescape = 0; |
383 bool canescape = false; |
384 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { |
384 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { |
385 for (int df = -1 ; df <= 1 && !canescape ; df++) { |
385 for (int df = -1 ; df <= 1 && !canescape ; df++) { |
386 if (!(dr == 0 && df == 0) && |
386 if (!(dr == 0 && df == 0) && |
387 isidx(opkingrow + dr) && isidx(opkingfile + df)) { |
387 isidx(opkingrow + dr) && isidx(opkingfile + df)) { |
388 |
388 |
453 gamestate_cleanup(&simulation); |
453 gamestate_cleanup(&simulation); |
454 |
454 |
455 return VALID_MOVE_SEMANTICS; |
455 return VALID_MOVE_SEMANTICS; |
456 } |
456 } |
457 |
457 |
458 _Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, |
458 bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, |
459 uint8_t color, Move *threats, uint8_t *threatcount) { |
459 uint8_t color, Move *threats, uint8_t *threatcount) { |
460 Move candidates[32]; |
460 Move candidates[32]; |
461 int candidatecount = 0; |
461 int candidatecount = 0; |
462 for (uint8_t r = 0 ; r < 8 ; r++) { |
462 for (uint8_t r = 0 ; r < 8 ; r++) { |
463 for (uint8_t f = 0 ; f < 8 ; f++) { |
463 for (uint8_t f = 0 ; f < 8 ; f++) { |
483 if (threatcount) { |
483 if (threatcount) { |
484 *threatcount = 0; |
484 *threatcount = 0; |
485 } |
485 } |
486 |
486 |
487 |
487 |
488 _Bool result = 0; |
488 bool result = false; |
489 |
489 |
490 for (int i = 0 ; i < candidatecount ; i++) { |
490 for (int i = 0 ; i < candidatecount ; i++) { |
491 if (validate_move_rules(gamestate, &(candidates[i])) |
491 if (validate_move_rules(gamestate, &(candidates[i])) |
492 == VALID_MOVE_SEMANTICS) { |
492 == VALID_MOVE_SEMANTICS) { |
493 result = 1; |
493 result = true; |
494 if (threats && threatcount) { |
494 if (threats && threatcount) { |
495 threats[(*threatcount)++] = candidates[i]; |
495 threats[(*threatcount)++] = candidates[i]; |
496 } |
496 } |
497 } |
497 } |
498 } |
498 } |
499 |
499 |
500 return result; |
500 return result; |
501 } |
501 } |
502 |
502 |
503 _Bool is_pinned(GameState *gamestate, Move *move) { |
503 bool is_pinned(GameState *gamestate, Move *move) { |
504 uint8_t color = move->piece & COLOR_MASK; |
504 uint8_t color = move->piece & COLOR_MASK; |
505 |
505 |
506 GameState simulation = gamestate_copy_sim(gamestate); |
506 GameState simulation = gamestate_copy_sim(gamestate); |
507 Move simmove = *move; |
507 Move simmove = *move; |
508 apply_move(&simulation, &simmove); |
508 apply_move(&simulation, &simmove); |
515 kingrow = row; |
515 kingrow = row; |
516 } |
516 } |
517 } |
517 } |
518 } |
518 } |
519 |
519 |
520 _Bool covered = is_covered(&simulation, |
520 bool covered = is_covered(&simulation, |
521 kingrow, kingfile, opponent_color(color)); |
521 kingrow, kingfile, opponent_color(color)); |
522 gamestate_cleanup(&simulation); |
522 gamestate_cleanup(&simulation); |
523 |
523 |
524 return covered; |
524 return covered; |
525 } |
525 } |
526 |
526 |
527 _Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, |
527 bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, |
528 uint8_t color, Move *threats, uint8_t *threatcount) { |
528 uint8_t color, Move *threats, uint8_t *threatcount) { |
529 |
529 |
530 if (threatcount) { |
530 if (threatcount) { |
531 *threatcount = 0; |
531 *threatcount = 0; |
532 } |
532 } |
533 |
533 |
534 Move candidates[16]; |
534 Move candidates[16]; |
535 uint8_t candidatecount; |
535 uint8_t candidatecount; |
536 if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { |
536 if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { |
537 |
537 |
538 _Bool result = 0; |
538 bool result = false; |
539 uint8_t kingfile = 0, kingrow = 0; |
539 uint8_t kingfile = 0, kingrow = 0; |
540 for (uint8_t row = 0 ; row < 8 ; row++) { |
540 for (uint8_t row = 0 ; row < 8 ; row++) { |
541 for (uint8_t file = 0 ; file < 8 ; file++) { |
541 for (uint8_t file = 0 ; file < 8 ; file++) { |
542 if (gamestate->board[row][file] == (color|KING)) { |
542 if (gamestate->board[row][file] == (color|KING)) { |
543 kingfile = file; |
543 kingfile = file; |
550 GameState simulation = gamestate_copy_sim(gamestate); |
550 GameState simulation = gamestate_copy_sim(gamestate); |
551 Move simmove = candidates[i]; |
551 Move simmove = candidates[i]; |
552 apply_move(&simulation, &simmove); |
552 apply_move(&simulation, &simmove); |
553 if (!is_covered(&simulation, kingrow, kingfile, |
553 if (!is_covered(&simulation, kingrow, kingfile, |
554 opponent_color(color))) { |
554 opponent_color(color))) { |
555 result = 1; |
555 result = true; |
556 if (threats && threatcount) { |
556 if (threats && threatcount) { |
557 threats[(*threatcount)++] = candidates[i]; |
557 threats[(*threatcount)++] = candidates[i]; |
558 } |
558 } |
559 } |
559 } |
560 } |
560 } |
561 |
561 |
562 return result; |
562 return result; |
563 } else { |
563 } else { |
564 return 0; |
564 return false; |
565 } |
565 } |
566 } |
566 } |
567 |
567 |
568 static int getlocation(GameState *gamestate, Move *move) { |
568 static int getlocation(GameState *gamestate, Move *move) { |
569 |
569 |
570 uint8_t color = move->piece & COLOR_MASK; |
570 uint8_t color = move->piece & COLOR_MASK; |
571 uint8_t piece = move->piece & PIECE_MASK; |
571 uint8_t piece = move->piece & PIECE_MASK; |
572 _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; |
572 bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:false; |
573 |
573 |
574 Move threats[16], *threat = NULL; |
574 Move threats[16], *threat = NULL; |
575 uint8_t threatcount; |
575 uint8_t threatcount; |
576 |
576 |
577 if (get_threats(gamestate, move->torow, move->tofile, color, |
577 if (get_threats(gamestate, move->torow, move->tofile, color, |
743 } else { |
743 } else { |
744 return INVALID_MOVE_SYNTAX; |
744 return INVALID_MOVE_SYNTAX; |
745 } |
745 } |
746 } |
746 } |
747 |
747 |
748 _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, |
748 bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, |
749 uint8_t color) { |
749 uint8_t color) { |
750 |
750 |
751 Move threats[16]; |
751 Move threats[16]; |
752 uint8_t threatcount; |
752 uint8_t threatcount; |
753 if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) { |
753 if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) { |
754 for (int i = 0 ; i < threatcount ; i++) { |
754 for (int i = 0 ; i < threatcount ; i++) { |
755 if (threats[i].piece != (color|KING)) { |
755 if (threats[i].piece != (color|KING)) { |
756 return 1; |
756 return true; |
757 } |
757 } |
758 } |
758 } |
759 return 0; |
759 return false; |
760 } else { |
760 } else { |
761 return 0; |
761 return false; |
762 } |
762 } |
763 } |
763 } |
764 |
764 |
765 uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, |
765 uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, |
766 uint8_t color) { |
766 uint8_t color) { |