/* * Add all pseudo-legal non-capturing moves that the given piece (N/B/Q/K) * can make, with the exception of castles. */ static void generate_piece_noncaptures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { move_t* moves = *moves_head; square_t to; if (piece_slide_type(piece) == NONE) { // not a sliding piece, just iterate over dest. squares for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; moves = add_move(pos, create_move(from, to, piece, NONE), moves); } } else { // a sliding piece, keep going until we hit something for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; while (pos->board[to] == EMPTY) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); to += *delta; } } } *moves_head = moves; }
/* * Add all pseudo-legal captures that the given pawn can make. */ static void generate_pawn_captures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { color_t side = pos->side_to_move; int cap_left = side == WHITE ? 15 : -15; int cap_right = side == WHITE ? 17 : -17; square_t to; rank_t r_rank = relative_rank[side][square_rank(from)]; move_t* moves = *moves_head; if (r_rank < RANK_7) { // non-promote captures to = from + cap_left; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } else if (to == pos->ep_square && pos->board[to] == EMPTY) { moves = add_move(pos, create_move_enpassant(from, to, piece, pos->board[to + pawn_push[side^1]]), moves); } to = from + cap_right; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } else if (to == pos->ep_square && pos->board[to] == EMPTY) { moves = add_move(pos, create_move_enpassant(from, to, piece, pos->board[to + pawn_push[side^1]]), moves); } } else { // capture/promotes to = from + cap_left; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, pos->board[to], promoted), moves); } } to = from + cap_right; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, pos->board[to], promoted), moves); } } } *moves_head = moves; }
int get_valid_move_count(int x, int y, enum cell_contents board[][BOARD_WIDTH]) { int count = 0; struct move move; /* check all four directions */ move = create_move(x, y, x - 2, y); if (is_valid_move(move, board, NULL)) count++; move = create_move(x, y, x + 2, y); if (is_valid_move(move, board, NULL)) count++; move = create_move(x, y, x, y - 2); if (is_valid_move(move, board, NULL)) count++; move = create_move(x, y, x, y + 2); if (is_valid_move(move, board, NULL)) count++; return count; }
/* * Generate all non-capturing, non-promoting pawn moves. */ static void generate_pawn_quiet_moves(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { color_t side = pos->side_to_move; square_t to; rank_t r_rank = relative_rank[side][square_rank(from)]; move_t* moves = *moves_head; to = from + pawn_push[side]; if (r_rank == RANK_7 || pos->board[to] != EMPTY) return; moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); to += pawn_push[side]; if (r_rank == RANK_2 && pos->board[to] == EMPTY) { // initial two-square push moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } *moves_head = moves; }
Move str_to_move(char *string) { for(int i = 0; i < 4; i += 1) if(string[i] == '\0') return 0; if(!((string[0] >= 'a' && string[0] <= 'h') && (string[1] >= '1' && string[1] <= '8') && (string[2] >= 'a' && string[2] <= 'h') && (string[3] >= '1' && string[3] <= '8'))) return 0; int from = ('8' - string[1] + 2) * 10 + (string[0] - 'a' + 1); int to = ('8' - string[3] + 2) * 10 + (string[2] - 'a' + 1); int broken = board[to]; int turn = 0; switch(string[4]) { case 'q': turn = create_figure(turn_to_move, QUEEN); break; case 'r': turn = create_figure(turn_to_move, ROOK); break; case 'b': turn = create_figure(turn_to_move, BISHOP); break; case 'n': turn = create_figure(turn_to_move, KNIGHT); break; } return create_move(from, to, broken, turn); }
int movegen(struct Game* game, int move_count) { U64 temp_move, temp_move2, temp_piece; U32 from, to, move; U64 free_squares = game->board[OCCUPIED][0]; if (game->to_move == WHITE) { /***************/ /* WHITE PAWNS */ /***************/ temp_move = step_up(game->board[PAWNS][WHITE]) & free_squares; temp_move2 = temp_move; /* single pushes */ while (temp_move) { to = bit_scan_forward(temp_move); if (to/8 == 7) { /* time for a promotion */ game->move_buffer[move_count++] = create_move(to-8,to,BISHOP_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to-8,to,KNIGHT_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to-8,to,ROOK_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to-8,to,QUEEN_PROMO_FLAG); } else game->move_buffer[move_count++] = create_move(to-8,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* double pushes */ temp_move2 = step_up(temp_move2) & free_squares & rank4; while (temp_move2) { to = bit_scan_forward(temp_move2); game->move_buffer[move_count++] = create_move(to-16,to,DOUBLE_PAWN_PUSH_FLAG); temp_move2 &= temp_move2 - 1; } /* captures */ /* TODO: add en passante capture */ temp_piece = game->board[PAWNS][WHITE]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move = pawn_attacks[WHITE][from] & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); if (to/8 == 7) { /* time for a promotion */ game->move_buffer[move_count++] = create_move(from,to,BISHOP_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,KNIGHT_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,ROOK_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,QUEEN_PROMO_CAPTURE_FLAG); } else game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /*****************/ /* WHITE KNIGHTS */ /*****************/ temp_piece = game->board[KNIGHTS][WHITE]; while (temp_piece) { from = bit_scan_forward(temp_piece); /* quiets */ temp_move = knight_table[from] & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = knight_table[from] & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /*****************/ /* WHITE BISHOPS */ /*****************/ temp_piece = game->board[BISHOPS][WHITE]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_bishop_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /***************/ /* WHITE ROOKS */ /***************/ temp_piece = game->board[ROOKS][WHITE]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_rook_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /****************/ /* WHITE QUEENS */ /****************/ temp_piece = game->board[QUEENS][WHITE]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_queen_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /**************/ /* WHITE KINGS */ /**************/ temp_piece = game->board[KINGS][WHITE]; from = bit_scan_forward(temp_piece); /* quiets */ temp_move = king_table[from] & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = king_table[from] & game->board[PIECES][BLACK]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } /* TODO: add castling moves here after writing is_attacked function */ } else { /* to_move == BLACK */ /***************/ /* BLACK PAWNS */ /***************/ temp_move = step_down(game->board[PAWNS][BLACK]) & free_squares; temp_move2 = temp_move; /* single pushes */ while (temp_move) { to = bit_scan_forward(temp_move); if (to/8 == 0) { /* time for a promotion */ game->move_buffer[move_count++] = create_move(to+8,to,BISHOP_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to+8,to,KNIGHT_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to+8,to,ROOK_PROMO_FLAG); game->move_buffer[move_count++] = create_move(to+8,to,QUEEN_PROMO_FLAG); } else game->move_buffer[move_count++] = create_move(to+8,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* double pushes */ temp_move2 = step_down(temp_move2) & free_squares & rank5; while (temp_move2) { to = bit_scan_forward(temp_move2); game->move_buffer[move_count++] = create_move(to+16,to,DOUBLE_PAWN_PUSH_FLAG); temp_move2 &= temp_move2 - 1; } /* captures */ /* TODO: add en passante capture */ temp_piece = game->board[PAWNS][BLACK]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move = pawn_attacks[BLACK][from] & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); if (to/8 == 7) { /* time for a promotion */ game->move_buffer[move_count++] = create_move(from,to,BISHOP_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,KNIGHT_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,ROOK_PROMO_CAPTURE_FLAG); game->move_buffer[move_count++] = create_move(from,to,QUEEN_PROMO_CAPTURE_FLAG); } else game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /*****************/ /* BLACK KNIGHTS */ /*****************/ temp_piece = game->board[KNIGHTS][BLACK]; while (temp_piece) { from = bit_scan_forward(temp_piece); /* quiets */ temp_move = knight_table[from] & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = knight_table[from] & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /*****************/ /* BLACK BISHOPS */ /*****************/ temp_piece = game->board[BISHOPS][BLACK]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_bishop_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /***************/ /* BLACK ROOKS */ /***************/ temp_piece = game->board[ROOKS][BLACK]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_rook_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /****************/ /* BLACK QUEENS */ /****************/ temp_piece = game->board[QUEENS][BLACK]; while (temp_piece) { from = bit_scan_forward(temp_piece); temp_move2 = get_queen_attacks(game->board[OCCUPIED][1], from); /* quiets */ temp_move = temp_move2 & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = temp_move2 & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } temp_piece &= temp_piece - 1; } /**************/ /* BLACK KINGS */ /**************/ temp_piece = game->board[KINGS][BLACK]; from = bit_scan_forward(temp_piece); /* quiets */ temp_move = king_table[from] & free_squares; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,QUIET_FLAG); temp_move &= temp_move - 1; } /* captures */ temp_move = king_table[from] & game->board[PIECES][WHITE]; while (temp_move) { to = bit_scan_forward(temp_move); game->move_buffer[move_count++] = create_move(from,to,CAPTURE_FLAG); temp_move &= temp_move - 1; } } return move_count; }
int generate_captures(Move *movelist) { int horizontal2 = turn_to_move == WHITE? 8 : 3; int horizontal7 = turn_to_move == WHITE? 3 : 8; int direction_of_pawns = turn_to_move == WHITE? -10: 10; int captures_of_pawns[2] = {direction_of_pawns + 1, direction_of_pawns - 1}; int place_of_king = turn_to_move == WHITE? place_of_white_king: place_of_black_king; int n = 0; for(int i = 0; i < 8; i += 1) { int tmp = place_of_king + moves_of_king[i]; if(get_color(board[tmp]) == not_turn_to_move) { movelist[n] = create_move(place_of_king, tmp, board[tmp], 0); n += 1; } } for(int i64 = 0; i64 < 64; i64 += 1) { int current_cell = board64[i64]; int figure = board[current_cell]; if(get_color(figure) != turn_to_move) continue; switch(get_value(figure)) { case QUEEN: for(int i = 0; i < 8; i += 1) { int inc = directions_of_queen[i]; int x = current_cell + inc; while(board[x] == EMPTY) x += inc; if(get_color(board[x]) == not_turn_to_move) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case ROOK: for(int i = 0; i < 4; i += 1) { int inc = directions_of_rook[i]; int x = current_cell + inc; while(board[x] == EMPTY) x += inc; if(get_color(board[x]) == not_turn_to_move) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case BISHOP: for(int i = 0; i < 4; i += 1) { int inc = directions_of_bishop[i]; int x = current_cell + inc; while(board[x] == EMPTY) x += inc; if(get_color(board[x]) == not_turn_to_move) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case KNIGHT: for(int i = 0; i < 8; i += 1) { int tmp = current_cell + moves_of_knight[i]; if(get_color(board[tmp]) == not_turn_to_move) { movelist[n] = create_move(current_cell, tmp, board[tmp], 0); n += 1; } } break; case PAWN: for(int i = 0; i < 2; i += 1) { int tmp = current_cell + captures_of_pawns[i]; if(get_color(board[tmp]) == not_turn_to_move) { movelist[n] = create_move(current_cell, tmp, board[tmp], 0); n += 1; } } } } for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); if(in_check(not_turn_to_move)) { movelist[i] = movelist[n - 1]; n -= 1; i -= 1; } unmake_move(i_move); } return n; }
int generate_moves(Move *movelist) { int horizontal2 = turn_to_move == WHITE? 8 : 3; int horizontal7 = turn_to_move == WHITE? 3 : 8; int direction_of_pawns = turn_to_move == WHITE? -10: 10; int captures_of_pawns[2] = {direction_of_pawns + 1, direction_of_pawns - 1}; int place_of_king = turn_to_move == WHITE? place_of_white_king: place_of_black_king; int n = 0; int king_castling, queen_castling; if(turn_to_move == WHITE) { king_castling = ply->castlings & K_castling; queen_castling = ply->castlings & Q_castling; } else { king_castling = ply->castlings & k_castling; queen_castling = ply->castlings & q_castling; } int is_in_check = in_check(turn_to_move); for(int i = 0; i < 8; i += 1) { int i_move = moves_of_king[i]; int tmp = place_of_king + i_move; if(board[tmp] == EMPTY || get_color(board[tmp]) == not_turn_to_move) { int i_move_is_possible = 0; Move tmp_move = create_move(place_of_king, tmp, board[tmp], 0); make_move(tmp_move); if(!in_check(not_turn_to_move)) { i_move_is_possible = 1; movelist[n] = tmp_move; n += 1; } unmake_move(tmp_move); if(is_in_check || !i_move_is_possible || board[tmp] != EMPTY) continue; if(i_move == 1 && king_castling && board[place_of_king + 2] == EMPTY) { movelist[n] = create_move(place_of_king, place_of_king + 2, 0, 0); n += 1; } if(i_move == -1 && queen_castling && board[place_of_king - 2] == EMPTY && board[place_of_king - 3] == EMPTY) { movelist[n] = create_move(place_of_king, place_of_king - 2, 0, 0); n += 1; } } } if(ply->en_passant) { for(int i = 0; i < 2; i += 1) { int tmp = ply->en_passant - captures_of_pawns[i]; if(board[tmp] == create_figure(turn_to_move, PAWN)) { movelist[n] = create_move(tmp, ply->en_passant, 0, 0); n += 1; } } } for(int i64 = 0; i64 < 64; i64 += 1) { int current_cell = board64[i64]; int figure = board[current_cell]; if(get_color(figure) != turn_to_move) continue; switch(get_value(figure)) { case QUEEN: for(int i = 0; i < 8; i += 1) { int inc = directions_of_queen[i]; int x = current_cell + inc; while(board[x] == EMPTY) { movelist[n] = create_move(current_cell, x, 0, 0); n += 1; x += inc; } if(get_color(board[x]) == not_turn_to_move ) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case ROOK: for(int i = 0; i < 4; i += 1) { int inc = directions_of_rook[i]; int x = current_cell + inc; while(board[x] == EMPTY) { movelist[n] = create_move(current_cell, x, 0, 0); n += 1; x += inc; } if(get_color(board[x]) == not_turn_to_move) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case BISHOP: for(int i = 0; i < 4; i += 1) { int inc = directions_of_bishop[i]; int x = current_cell + inc; while(board[x] == EMPTY) { movelist[n] = create_move(current_cell, x, 0, 0); n += 1; x += inc; } if(get_color(board[x]) == not_turn_to_move) { movelist[n] = create_move(current_cell, x, board[x], 0); n += 1; } } break; case KNIGHT: for(int i = 0; i < 8; i += 1) { int tmp = current_cell + moves_of_knight[i]; if(board[tmp] == EMPTY || get_color(board[tmp]) == not_turn_to_move) { movelist[n] = create_move(current_cell, tmp, board[tmp], 0); n += 1; } } break; case PAWN: ;int tmp = current_cell + direction_of_pawns; if(board[tmp] == EMPTY) { if(current_cell/10 == horizontal7) { for(int j = 0; j < 4; j += 1) { movelist[n] = create_move(current_cell, tmp, 0, create_figure(turn_to_move, turn_figures[j])); n += 1; } } else { movelist[n] = create_move(current_cell, tmp, 0, 0); n += 1; } tmp += direction_of_pawns; if(board[tmp] == EMPTY && current_cell/10 == horizontal2) { movelist[n] = create_move(current_cell, tmp, 0, 0); n += 1; } } for(int i = 0; i < 2; i += 1) { int tmp = current_cell + captures_of_pawns[i]; if(get_color(board[tmp]) == not_turn_to_move) { if(current_cell/10 == horizontal7) { for(int j = 0; j < 4; j += 1) { movelist[n] = create_move(current_cell, tmp, board[tmp], create_figure(turn_to_move, turn_figures[j])); n += 1; } } else { movelist[n] = create_move(current_cell, tmp, board[tmp], 0); n += 1; } } } } } for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); if(in_check(not_turn_to_move)) { movelist[i] = movelist[n - 1]; n -= 1; i -= 1; } unmake_move(i_move); } return n; }
/* * Add all pseudo-legal captures that the given piece (N/B/Q/K) can make. */ static void generate_piece_captures(const position_t* pos, square_t from, piece_t piece, move_t** moves_head) { move_t* moves = *moves_head; square_t to; // Note: I unrolled all these loops to handle each direction explicitly. // The idea was to increase performance, but it's only about 1% faster // for much more code, so it's possible I'll change this back later. switch (piece_type(piece)) { case KING: to = from - 17; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 16; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 15; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 1; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 1; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 15; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 16; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 17; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case KNIGHT: to = from - 33; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 31; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 18; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from - 14; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 14; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 18; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 31; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } to = from + 33; if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case BISHOP: for (to=from-17; pos->board[to]==EMPTY; to-=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-15; pos->board[to]==EMPTY; to-=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+15; pos->board[to]==EMPTY; to+=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+17; pos->board[to]==EMPTY; to+=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case ROOK: for (to=from-16; pos->board[to]==EMPTY; to-=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-1; pos->board[to]==EMPTY; to-=1) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+1; pos->board[to]==EMPTY; to+=1) {} if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+16; pos->board[to]==EMPTY; to+=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; case QUEEN: for (to=from-17; pos->board[to]==EMPTY; to-=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-16; pos->board[to]==EMPTY; to-=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-15; pos->board[to]==EMPTY; to-=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from-1; pos->board[to]==EMPTY; to-=1) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+1; pos->board[to]==EMPTY; to+=1) {} if (pos->board[to] != EMPTY && can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+15; pos->board[to]==EMPTY; to+=15) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+16; pos->board[to]==EMPTY; to+=16) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } for (to=from+17; pos->board[to]==EMPTY; to+=17) {} if (can_capture(piece, pos->board[to])) { moves = add_move(pos, create_move(from, to, piece, pos->board[to]), moves); } break; default: assert(false); } *moves_head = moves; }
/* * Generate all non-capturing, non-promoting, pseudo-legal checks. Used for * quiescent move generation. */ int generate_pseudo_checks(const position_t* pos, move_t* moves) { move_t* moves_head = moves; color_t side = pos->side_to_move, other_side = side^1; square_t king_sq = pos->pieces[other_side][0]; for (int i = 0; i < pos->num_pawns[side]; ++i) { square_t from = pos->pawns[side][i]; square_t to = INVALID_SQUARE; piece_t piece = pos->board[from]; // Figure out whether or not we can discover check by moving. direction_t discover_check_dir = 0; bool will_discover_check; const attack_data_t* king_atk = &get_attack_data(from, king_sq); if ((king_atk->possible_attackers & Q_FLAG) == 0) { discover_check_dir = 0; } else { direction_t king_dir = king_atk->relative_direction; square_t sq; for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {} if (sq == king_sq) { // Nothing between us and the king. Is there anything // behind us to do the check when we move? for (sq = from-king_dir; pos->board[sq] == EMPTY; sq -= king_dir) {} if (side == piece_color(pos->board[sq]) && (king_atk->possible_attackers & get_piece_flag(pos->board[sq]))) { discover_check_dir = king_dir; } } } // Generate checking moves. will_discover_check = discover_check_dir && abs(discover_check_dir)!=N; to = from + pawn_push[side]; if (pos->board[to] != EMPTY) continue; rank_t r_rank = relative_rank[side][square_rank(from)]; if (r_rank == RANK_7) continue; // non-promotes only for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { if (will_discover_check || to + *delta == king_sq) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } to += pawn_push[side]; if (r_rank == RANK_2 && pos->board[to] == EMPTY) { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { if (will_discover_check || to + *delta == king_sq) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } } } for (int i = 0; i < pos->num_pieces[side]; ++i) { square_t from = pos->pieces[side][i]; square_t to = INVALID_SQUARE; piece_t piece = pos->board[from]; // Figure out whether or not we can discover check by moving. direction_t discover_check_dir = 0; bool will_discover_check; const attack_data_t* king_atk = &get_attack_data(from, king_sq); if ((king_atk->possible_attackers & Q_FLAG) == 0) { discover_check_dir = 0; } else { direction_t king_dir = king_atk->relative_direction; square_t sq; for (sq = from+king_dir; pos->board[sq] == EMPTY; sq+=king_dir) {} if (sq == king_sq) { // Nothing between us and the king. Is there anything // behind us to do the check when we move? for (sq = from - king_dir; pos->board[sq] == EMPTY; sq -= king_dir) {} if (side == piece_color(pos->board[sq]) && (king_atk->possible_attackers & get_piece_flag(pos->board[sq]))) { discover_check_dir = king_dir; } } } // Generate checking moves. if (piece_is_type(piece, KNIGHT)) { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; if (discover_check_dir || possible_attack(to, king_sq, WN)) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } } else { for (const direction_t* delta = piece_deltas[piece]; *delta; ++delta) { for (to = from+*delta; pos->board[to] == EMPTY; to+=*delta) { will_discover_check = discover_check_dir && abs(discover_check_dir) != abs(*delta); if (will_discover_check) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); continue; } if (possible_attack(to, king_sq, piece)) { const direction_t to_king = direction(to, king_sq); square_t x = to + to_king; for (; pos->board[x] == EMPTY; x+=to_king) {} if (x == king_sq) { moves = add_move(pos, create_move(from, to, piece, NONE), moves); } } } } } } *moves = 0; return moves-moves_head; }
/* * Generate all moves that evade check in the given position. This is purely * legal move generation; no pseudo-legal moves. */ int generate_evasions(const position_t* pos, move_t* moves) { assert(pos->is_check && pos->board[pos->check_square]); move_t* moves_head = moves; color_t side = pos->side_to_move, other_side = side^1; square_t king_sq = pos->pieces[side][0]; square_t check_sq = pos->check_square; piece_t king = create_piece(side, KING); piece_t checker = pos->board[check_sq]; // Generate king moves. // Don't let the king mask its possible destination squares in calls // to is_square_attacked. square_t from = king_sq, to = INVALID_SQUARE; ((position_t*)pos)->board[king_sq] = EMPTY; for (const direction_t* delta = piece_deltas[king]; *delta; ++delta) { to = from + *delta; piece_t capture = pos->board[to]; if (capture != EMPTY && !can_capture(king, capture)) continue; if (is_square_attacked((position_t*)pos,to,other_side)) continue; ((position_t*)pos)->board[king_sq] = king; moves = add_move(pos, create_move(from, to, king, capture), moves); ((position_t*)pos)->board[king_sq] = EMPTY; } ((position_t*)pos)->board[king_sq] = king; // If there are multiple checkers, only king moves are possible. if (pos->is_check > 1) { *moves = 0; return moves-moves_head; } // First, the most common case: a check that can be evaded via an // en passant capture. Note that if we're in check and an en passant // capture is available, the only way the en passant capture would evade // the check is if it's the newly moved pawn that's checking us. direction_t pin_dir; if (pos->ep_square != EMPTY && check_sq+pawn_push[side] == pos->ep_square && pos->board[pos->ep_square] == EMPTY) { piece_t our_pawn = create_piece(side, PAWN); to = pos->ep_square; for (int i=0; i<2; ++i) { from = to-piece_deltas[our_pawn][i]; if (pos->board[from] && pos->board[from] == our_pawn) { pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; moves = add_move(pos, create_move_enpassant(from, to, our_pawn, checker), moves); } } } // Generate captures of the checker. for (int i = 0; i < pos->num_pawns[side]; ++i) { from = pos->pawns[side][i]; piece_t piece = create_piece(side, PAWN); pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (!possible_attack(from, check_sq, piece)) continue; if (relative_rank[side][square_rank(from)] == RANK_7) { // Capture and promote. for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, check_sq, piece, checker, promoted), moves); } } else { moves = add_move(pos, create_move(from, check_sq, piece, checker), moves); } } for (int i = 1; i < pos->num_pieces[side]; ++i) { from = pos->pieces[side][i]; piece_t piece = pos->board[from]; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (!possible_attack(from, check_sq, piece)) continue; if (piece_slide_type(piece) == NONE) { moves = add_move(pos, create_move(from, check_sq, piece, checker), moves); } else { // A sliding piece, keep going until we hit something. direction_t check_dir = direction(from, check_sq); for (to=from+check_dir; pos->board[to] == EMPTY; to+=check_dir) {} if (to == check_sq) { moves = add_move(pos, create_move(from, to, piece, checker), moves); continue; } } } if (piece_slide_type(checker) == NONE) { *moves = 0; return moves-moves_head; } // A slider is doing the checking; generate blocking moves. direction_t block_dir = direction(check_sq, king_sq); for (int i = 0; i < pos->num_pawns[side]; ++i) { from = pos->pawns[side][i]; piece_t piece = create_piece(side, PAWN); direction_t k_dir; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; to = from + pawn_push[side]; if (pos->board[to] != EMPTY) continue; rank_t rank = relative_rank[side][square_rank(from)]; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { if (rank == RANK_7) { // Block and promote. for (piece_t promoted=QUEEN; promoted > PAWN; --promoted) { moves = add_move(pos, create_move_promote(from, to, piece, EMPTY, promoted), moves); } } else { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } if (rank != RANK_2) continue; to += pawn_push[side]; if (pos->board[to]) continue; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } for (int i=1; i<pos->num_pieces[side]; ++i) { from = pos->pieces[side][i]; piece_t piece = pos->board[from]; direction_t k_dir; pin_dir = pin_direction(pos, from, king_sq); if (pin_dir) continue; if (piece_is_type(piece, KNIGHT)) { for (const direction_t* delta=piece_deltas[piece]; *delta; ++delta) { to = from + *delta; if (pos->board[to] != EMPTY) continue; k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); } } } else { for (const direction_t* delta=piece_deltas[piece]; *delta; ++delta) { for (to = from+*delta; pos->board[to] == EMPTY; to+=*delta) { k_dir = direction(to, king_sq); if (k_dir == block_dir && ((king_sq < to && check_sq > to) || (king_sq > to && check_sq < to))) { moves = add_move(pos, create_move(from, to, piece, EMPTY), moves); break; } } } } } *moves = 0; return moves-moves_head; }