| 104 |
104 |
| 105 Color current_color(const GameState *gamestate) { |
105 Color current_color(const GameState *gamestate) { |
| 106 return (gamestate->movecount % 2 == 0) ? WHITE : BLACK; |
106 return (gamestate->movecount % 2 == 0) ? WHITE : BLACK; |
| 107 } |
107 } |
| 108 |
108 |
| 109 /* MUST be called BETWEEN validating AND applying a move to work correctly */ |
|
| 110 static void format_move(const GameState *gamestate, Move *move) { |
|
| 111 char *string = &(move->string[0]); |
|
| 112 |
|
| 113 /* at least 8 characters should be available, wipe them out */ |
|
| 114 memset(string, 0, 8); |
|
| 115 |
|
| 116 unsigned int idx; |
|
| 117 if (piece_type(move->piece) == KING && |
|
| 118 abs(move->tofile-move->fromfile) == 2) { |
|
| 119 /* special formats for castling */ |
|
| 120 if (move->tofile==fileidx('c')) { |
|
| 121 memcpy(string, "O-O-O", 5); |
|
| 122 idx = 5; |
|
| 123 } else { |
|
| 124 memcpy(string, "O-O", 3); |
|
| 125 idx = 3; |
|
| 126 } |
|
| 127 } else { |
|
| 128 /* start by notating the piece character */ |
|
| 129 string[0] = getpiecechr(move->piece); |
|
| 130 idx = string[0] ? 1 : 0; |
|
| 131 |
|
| 132 /* find out how many source information we do need */ |
|
| 133 if (piece_type(move->piece) == PAWN) { |
|
| 134 if (move->capture) { |
|
| 135 string[idx++] = filechr(move->fromfile); |
|
| 136 } |
|
| 137 } else if (piece_type(move->piece) != KING) { |
|
| 138 /* resolve ambiguities, if any */ |
|
| 139 Move candidates[16]; |
|
| 140 size_t ccount; |
|
| 141 if (get_real_candidates(gamestate, move->torow, move->tofile, |
|
| 142 piece_color(move->piece), candidates, &ccount)) { |
|
| 143 unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; |
|
| 144 for (size_t i = 0 ; i < ccount ; i++) { |
|
| 145 if (candidates[i].piece == move->piece) { |
|
| 146 ambpiece++; |
|
| 147 if (candidates[i].fromrow == move->fromrow) { |
|
| 148 ambrows++; |
|
| 149 } |
|
| 150 if (candidates[i].fromfile == move->fromfile) { |
|
| 151 ambfiles++; |
|
| 152 } |
|
| 153 } |
|
| 154 } |
|
| 155 /* neither file, nor row are ambiguous, name file */ |
|
| 156 if (ambpiece > 1 && ambrows == 1 && ambfiles == 1) { |
|
| 157 /* this is most likely the case with Knights |
|
| 158 * in diagonal opposition */ |
|
| 159 string[idx++] = filechr(move->fromfile); |
|
| 160 } else { |
|
| 161 /* ambiguous row, name file */ |
|
| 162 if (ambrows > 1) { |
|
| 163 string[idx++] = filechr(move->fromfile); |
|
| 164 } |
|
| 165 /* ambiguous file, name row */ |
|
| 166 if (ambfiles > 1) { |
|
| 167 string[idx++] = rowchr(move->fromrow); |
|
| 168 } |
|
| 169 } |
|
| 170 } |
|
| 171 } |
|
| 172 |
|
| 173 /* capturing? */ |
|
| 174 if (move->capture) { |
|
| 175 string[idx++] = 'x'; |
|
| 176 } |
|
| 177 |
|
| 178 /* destination */ |
|
| 179 string[idx++] = filechr(move->tofile); |
|
| 180 string[idx++] = rowchr(move->torow); |
|
| 181 |
|
| 182 /* promotion? */ |
|
| 183 if (move->promotion) { |
|
| 184 string[idx++] = '='; |
|
| 185 string[idx++] = getpiecechr(move->promotion); |
|
| 186 } |
|
| 187 } |
|
| 188 |
|
| 189 /* check? */ |
|
| 190 if (move->checkmate) { |
|
| 191 string[idx++] = '#'; |
|
| 192 } else if (move->check) { |
|
| 193 string[idx++] = '+'; |
|
| 194 } |
|
| 195 } |
|
| 196 |
|
| 197 static void calc_movetime(GameState *gamestate, Move *move) { |
109 static void calc_movetime(GameState *gamestate, Move *move) { |
| 198 /* only if move has no time info, compute it */ |
110 /* only if move has no time info, compute it */ |
| 199 if (move->movetime > 0) return; |
111 if (move->movetime > 0) return; |
| 200 |
112 |
| 201 struct timeval curtimestamp; |
113 struct timeval curtimestamp; |
| 618 } |
530 } |
| 619 } |
531 } |
| 620 } |
532 } |
| 621 gamestate_cleanup(&simulation); |
533 gamestate_cleanup(&simulation); |
| 622 return canescape ? 1 : 2; |
534 return canescape ? 1 : 2; |
| |
535 } |
| |
536 |
| |
537 |
| |
538 static void format_move_impl(const GameState *gamestate, Move *move) { |
| |
539 char *string = &(move->string[0]); |
| |
540 |
| |
541 /* at least 8 characters should be available, wipe them out */ |
| |
542 memset(string, 0, 8); |
| |
543 |
| |
544 unsigned int idx; |
| |
545 if (piece_type(move->piece) == KING && |
| |
546 abs(move->tofile-move->fromfile) == 2) { |
| |
547 /* special formats for castling */ |
| |
548 if (move->tofile==fileidx('c')) { |
| |
549 memcpy(string, "O-O-O", 5); |
| |
550 idx = 5; |
| |
551 } else { |
| |
552 memcpy(string, "O-O", 3); |
| |
553 idx = 3; |
| |
554 } |
| |
555 } else { |
| |
556 /* start by notating the piece character */ |
| |
557 string[0] = getpiecechr(move->piece); |
| |
558 idx = string[0] ? 1 : 0; |
| |
559 |
| |
560 /* find out how many source information we do need */ |
| |
561 if (piece_type(move->piece) == PAWN) { |
| |
562 if (move->capture) { |
| |
563 string[idx++] = filechr(move->fromfile); |
| |
564 } |
| |
565 } else if (piece_type(move->piece) != KING) { |
| |
566 /* resolve ambiguities, if any */ |
| |
567 Move candidates[16]; |
| |
568 size_t ccount; |
| |
569 if (get_real_candidates(gamestate, move->torow, move->tofile, |
| |
570 piece_color(move->piece), candidates, &ccount)) { |
| |
571 unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; |
| |
572 for (size_t i = 0 ; i < ccount ; i++) { |
| |
573 if (candidates[i].piece == move->piece) { |
| |
574 ambpiece++; |
| |
575 if (candidates[i].fromrow == move->fromrow) { |
| |
576 ambrows++; |
| |
577 } |
| |
578 if (candidates[i].fromfile == move->fromfile) { |
| |
579 ambfiles++; |
| |
580 } |
| |
581 } |
| |
582 } |
| |
583 /* neither file, nor row are ambiguous, name file */ |
| |
584 if (ambpiece > 1 && ambrows == 1 && ambfiles == 1) { |
| |
585 /* this is most likely the case with Knights |
| |
586 * in diagonal opposition */ |
| |
587 string[idx++] = filechr(move->fromfile); |
| |
588 } else { |
| |
589 /* ambiguous row, name file */ |
| |
590 if (ambrows > 1) { |
| |
591 string[idx++] = filechr(move->fromfile); |
| |
592 } |
| |
593 /* ambiguous file, name row */ |
| |
594 if (ambfiles > 1) { |
| |
595 string[idx++] = rowchr(move->fromrow); |
| |
596 } |
| |
597 } |
| |
598 } |
| |
599 } |
| |
600 |
| |
601 /* capturing? */ |
| |
602 if (move->capture) { |
| |
603 string[idx++] = 'x'; |
| |
604 } |
| |
605 |
| |
606 /* destination */ |
| |
607 string[idx++] = filechr(move->tofile); |
| |
608 string[idx++] = rowchr(move->torow); |
| |
609 |
| |
610 /* promotion? */ |
| |
611 if (move->promotion) { |
| |
612 string[idx++] = '='; |
| |
613 string[idx++] = getpiecechr(move->promotion); |
| |
614 } |
| |
615 } |
| |
616 |
| |
617 /* check? */ |
| |
618 if (move->checkmate) { |
| |
619 string[idx++] = '#'; |
| |
620 } else if (move->check) { |
| |
621 string[idx++] = '+'; |
| |
622 } |
| |
623 } |
| |
624 |
| |
625 void format_move(const GameState *gamestate, Move *move) { |
| |
626 /* correct check/checkmate flags */ |
| |
627 move->check = move->checkmate = false; |
| |
628 switch (determine_check_or_checkmate(gamestate, move)) { |
| |
629 case 2: move->checkmate = true; |
| |
630 case 1: move->check = true; |
| |
631 } |
| |
632 |
| |
633 /* format the move string */ |
| |
634 format_move_impl(gamestate, move); |
| 623 } |
635 } |
| 624 |
636 |
| 625 static int validate_move_rules(const GameState *gamestate, const Move *move) { |
637 static int validate_move_rules(const GameState *gamestate, const Move *move) { |
| 626 assert((move->piece & ~(PIECE_MASK|COLOR_MASK)) == 0); |
638 assert((move->piece & ~(PIECE_MASK|COLOR_MASK)) == 0); |
| 627 |
639 |
| 1160 case 1: move->check = true; |
1172 case 1: move->check = true; |
| 1161 } |
1173 } |
| 1162 } |
1174 } |
| 1163 |
1175 |
| 1164 /* format the move string */ |
1176 /* format the move string */ |
| 1165 format_move(gamestate, move); |
1177 format_move_impl(gamestate, move); |
| 1166 } |
1178 } |
| 1167 } |
1179 } |
| 1168 return result; |
1180 return result; |
| 1169 } |
1181 } |
| 1170 |
1182 |
| 1171 int eval_move_lazy(const GameState *gamestate, |
1183 int eval_move(const GameState *gamestate, |
| 1172 const char *mstr, Color color, Move *move) { |
1184 const char *mstr, Color color, Move *move) { |
| 1173 return eval_move2(gamestate, mstr, color, move, true); |
1185 return eval_move2(gamestate, mstr, color, move, true); |
| 1174 } |
1186 } |
| 1175 |
1187 |
| 1176 int eval_move(const GameState *gamestate, |
1188 int eval_move_strict(const GameState *gamestate, |
| 1177 const char *mstr, Color color, Move *move) { |
1189 const char *mstr, Color color, Move *move) { |
| 1178 return eval_move2(gamestate, mstr, color, move, false); |
1190 return eval_move2(gamestate, mstr, color, move, false); |
| 1179 } |
1191 } |
| 1180 |
1192 |
| 1181 int check_move(const char *mstr, Color color) { |
1193 int check_move(const char *mstr, Color color) { |