| 223 move->movetime.tv_usec = (int32_t) micros; |
223 move->movetime.tv_usec = (int32_t) micros; |
| 224 } |
224 } |
| 225 } |
225 } |
| 226 } |
226 } |
| 227 |
227 |
| |
228 size_t piece_moves_allowed(const GameState *gamestate, |
| |
229 Row r, File f, Move *moves) { |
| |
230 Piece p = piece_at(gamestate, r, f); |
| |
231 Color c = piece_color(p); |
| |
232 switch (piece_type(p)) { |
| |
233 case KING: |
| |
234 return king_moves_allowed(gamestate, c, r, f, moves); |
| |
235 case QUEEN: |
| |
236 return queen_moves_allowed(gamestate, c, r, f, moves); |
| |
237 case ROOK: |
| |
238 return rook_moves_allowed(gamestate, c, r, f, moves); |
| |
239 case KNIGHT: |
| |
240 return knight_moves_allowed(gamestate, c, r, f, moves); |
| |
241 case BISHOP: |
| |
242 return bishop_moves_allowed(gamestate, c, r, f, moves); |
| |
243 case PAWN: |
| |
244 return pawn_moves_allowed(gamestate, c, r, f, moves); |
| |
245 default: |
| |
246 return 0; |
| |
247 } |
| |
248 } |
| |
249 |
| |
250 static bool is_stalemate(const GameState *gamestate) { |
| |
251 Color next_player = gamestate->movecount % 2 == 0 ? WHITE : BLACK; |
| |
252 |
| |
253 /* scan the board for pieces of the next player's color */ |
| |
254 Move moves[QUEEN_MOVES_MAX]; |
| |
255 for (Row r = 0; r < 8; r++) { |
| |
256 for (File f = 0; f < 8; f++) { |
| |
257 if (piece_color(piece_at(gamestate, r, f)) == next_player |
| |
258 && piece_moves_allowed(gamestate, r, f, moves) > 0) { |
| |
259 return false; |
| |
260 } |
| |
261 } |
| |
262 } |
| |
263 |
| |
264 return true; |
| |
265 } |
| |
266 |
| 228 char getpiecechr(Piece piece) { |
267 char getpiecechr(Piece piece) { |
| 229 switch (piece_type(piece)) { |
268 switch (piece_type(piece)) { |
| 230 case ROOK: return 'R'; |
269 case ROOK: return 'R'; |
| 231 case KNIGHT: return 'N'; |
270 case KNIGHT: return 'N'; |
| 232 case BISHOP: return 'B'; |
271 case BISHOP: return 'B'; |
| 269 case 'K': return mkpiece(KING, color); |
308 case 'K': return mkpiece(KING, color); |
| 270 default: return 0; |
309 default: return 0; |
| 271 } |
310 } |
| 272 } |
311 } |
| 273 |
312 |
| 274 void apply_move(GameState *gamestate, Move *move) { |
313 static void apply_move_internal(GameState *gamestate, Move *move) { |
| 275 /* en passant capture */ |
314 /* en passant capture */ |
| 276 if (move->capture && piece_type(move->piece) == PAWN && |
315 if (move->capture && piece_type(move->piece) == PAWN && |
| 277 piece_at(gamestate, mdst(move)) == 0) { |
316 piece_at(gamestate, mdst(move)) == 0) { |
| 278 piece_remove(gamestate, move->fromrow, move->tofile); |
317 piece_remove(gamestate, move->fromrow, move->tofile); |
| 279 } |
318 } |
| 339 |
378 |
| 340 /* did this move checkmate the other king? */ |
379 /* did this move checkmate the other king? */ |
| 341 gamestate->checkmate = move->checkmate; |
380 gamestate->checkmate = move->checkmate; |
| 342 } |
381 } |
| 343 |
382 |
| |
383 void apply_move(GameState *gamestate, Move *move) { |
| |
384 apply_move_internal(gamestate, move); |
| |
385 if (!gamestate->checkmate) { |
| |
386 gamestate->stalemate = is_stalemate(gamestate); |
| |
387 } |
| |
388 } |
| |
389 |
| 344 void gamestate_at_move(const GameState *gamestate, |
390 void gamestate_at_move(const GameState *gamestate, |
| 345 unsigned move_number, GameState *replay) { |
391 unsigned move_number, GameState *replay) { |
| 346 gamestate_init(replay); |
392 gamestate_init(replay); |
| 347 memcpy(&replay->info, &gamestate->info, sizeof(GameInfo)); |
393 memcpy(&replay->info, &gamestate->info, sizeof(GameInfo)); |
| 348 replay->review = true; |
394 replay->review = true; |
| 359 const GameState *gamestate, const Move *move) { |
405 const GameState *gamestate, const Move *move) { |
| 360 |
406 |
| 361 /* simulate the move */ |
407 /* simulate the move */ |
| 362 GameState simulation = gamestate_copy_sim(gamestate); |
408 GameState simulation = gamestate_copy_sim(gamestate); |
| 363 Move simmove = *move; |
409 Move simmove = *move; |
| 364 apply_move(&simulation, &simmove); |
410 apply_move_internal(&simulation, &simmove); |
| 365 |
411 |
| 366 /* find the opposing king */ |
412 /* find the opposing king */ |
| 367 Color piececolor = piece_color(move->piece); |
413 Color piececolor = piece_color(move->piece); |
| 368 Color oppcolor = opponent_color(piececolor); |
414 Color oppcolor = opponent_color(piececolor); |
| 369 File opkingfile = 0; |
415 File opkingfile = 0; |
| 415 move_retaliate.fromrow = opkingrow; |
461 move_retaliate.fromrow = opkingrow; |
| 416 move_retaliate.fromfile = opkingfile; |
462 move_retaliate.fromfile = opkingfile; |
| 417 move_retaliate.torow = er; |
463 move_retaliate.torow = er; |
| 418 move_retaliate.tofile = ef; |
464 move_retaliate.tofile = ef; |
| 419 move_retaliate.capture = true; |
465 move_retaliate.capture = true; |
| 420 apply_move(&sim_retaliate, &move_retaliate); |
466 apply_move_internal(&sim_retaliate, &move_retaliate); |
| 421 canescape = !is_covered(&sim_retaliate, er, ef, piececolor); |
467 canescape = !is_covered(&sim_retaliate, er, ef, piececolor); |
| 422 gamestate_cleanup(&sim_retaliate); |
468 gamestate_cleanup(&sim_retaliate); |
| 423 continue; |
469 continue; |
| 424 } |
470 } |
| 425 |
471 |
| 558 } |
604 } |
| 559 |
605 |
| 560 /* test if the move would expose our own king */ |
606 /* test if the move would expose our own king */ |
| 561 GameState simulation = gamestate_copy_sim(gamestate); |
607 GameState simulation = gamestate_copy_sim(gamestate); |
| 562 Move simmove = *move; |
608 Move simmove = *move; |
| 563 apply_move(&simulation, &simmove); |
609 apply_move_internal(&simulation, &simmove); |
| 564 Color piececolor = piece_color(move->piece); |
610 Color piececolor = piece_color(move->piece); |
| 565 Color oppcolor = opponent_color(piececolor); |
611 Color oppcolor = opponent_color(piececolor); |
| 566 File kingfile = 0; |
612 File kingfile = 0; |
| 567 Row kingrow = 0; |
613 Row kingrow = 0; |
| 568 for (Row row = 0 ; row < 8 ; row++) { |
614 for (Row row = 0 ; row < 8 ; row++) { |
| 584 result = PIECE_PINNED; |
630 result = PIECE_PINNED; |
| 585 } |
631 } |
| 586 } |
632 } |
| 587 } |
633 } |
| 588 gamestate_cleanup(&simulation); |
634 gamestate_cleanup(&simulation); |
| |
635 |
| |
636 if (result != VALID_MOVE_SEMANTICS) { |
| |
637 return result; |
| |
638 } |
| 589 |
639 |
| 590 /* validate check and checkmate flags */ |
640 /* validate check and checkmate flags */ |
| 591 int cocm = determine_check_or_checkmate(gamestate, move); |
641 int cocm = determine_check_or_checkmate(gamestate, move); |
| 592 if (cocm == 2) { |
642 if (cocm == 2) { |
| 593 if (!move->checkmate) { |
643 if (!move->checkmate) { |
| 720 bool is_pinned(const GameState *gamestate, const Move *move) { |
770 bool is_pinned(const GameState *gamestate, const Move *move) { |
| 721 Color color = piece_color(move->piece); |
771 Color color = piece_color(move->piece); |
| 722 |
772 |
| 723 GameState simulation = gamestate_copy_sim(gamestate); |
773 GameState simulation = gamestate_copy_sim(gamestate); |
| 724 Move simmove = *move; |
774 Move simmove = *move; |
| 725 apply_move(&simulation, &simmove); |
775 apply_move_internal(&simulation, &simmove); |
| 726 |
776 |
| 727 File kingfile = 0; |
777 File kingfile = 0; |
| 728 Row kingrow = 0; |
778 Row kingrow = 0; |
| 729 for (Row row = 0 ; row < 8 ; row++) { |
779 for (Row row = 0 ; row < 8 ; row++) { |
| 730 for (File file = 0 ; file < 8 ; file++) { |
780 for (File file = 0 ; file < 8 ; file++) { |
| 1134 bool check_threefold_repetition(const GameState *gamestate) { |
1184 bool check_threefold_repetition(const GameState *gamestate) { |
| 1135 // TODO: implement threefold repetition detection |
1185 // TODO: implement threefold repetition detection |
| 1136 return false; |
1186 return false; |
| 1137 } |
1187 } |
| 1138 |
1188 |
| 1139 size_t filter_moves_allowed(GameState *gamestate, |
1189 size_t filter_moves_allowed(const GameState *gamestate, |
| 1140 Color c, Row r, File f, Move *moves, moves_generator_func func) { |
1190 Color c, Row r, File f, Move *moves, moves_generator_func func) { |
| 1141 |
1191 |
| 1142 /* worst case: the queen has the most moves */ |
1192 /* worst case: the queen has the most moves */ |
| 1143 Move candidates[QUEEN_MOVES_MAX]; |
1193 Move candidates[QUEEN_MOVES_MAX]; |
| 1144 size_t candidatecount = func(gamestate, c, r, f, candidates); |
1194 size_t candidatecount = func(gamestate, c, r, f, candidates); |