src/chess/rules.c

changeset 170
bde99d803caf
parent 169
9962f5d98764
equal deleted inserted replaced
169:9962f5d98764 170:bde99d803caf
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);

mercurial