Ejemplo n.º 1
0
int play(int me, int opponent, int row, int col, bool first_player, move_t **moves) {

  bool can_capture_right, can_capture_left;
  move_t *moves_right, *moves_left;
  int score_right = 0;
  int score_left = 0;

  if (me == BLACK) {
    D printf("BLACK: ");

    can_capture_left = can_capture(me,opponent,row,col,row+1,col+1,row+2,col+2);
    can_capture_right = can_capture(me,opponent,row,col,row+1,col-1,row+2,col-2);
   
    D printf(" From (%d,%d): Right? %s Left? %s\n",row,col,(can_capture_right ? "Yes" : "No"),
	   (can_capture_left ? "Yes" : "No"));

    if (can_capture_left)
      score_left = 1 + test_capture(me,opponent,row,col,row+1,col+1,row+2,col+2,first_player,&moves_left);
    if (can_capture_right)
      score_right = 1 + test_capture(me,opponent,row,col,row+1,col-1,row+2,col-2,first_player,&moves_right);

    moves_left = move_gen(row+2,col+2,moves_left);
    moves_right = move_gen(row+2,col-2,moves_right);

  } else {

    D printf("WHITE: ");

    can_capture_left = can_capture(me,opponent,row,col,row-1,col-1,row-2,col-2);
    can_capture_right = can_capture(me,opponent,row,col,row-1,col+1,row-2,col+2);

    if (can_capture_left)
      score_left = 1 + test_capture(me,opponent,row,col,row-1,col-1,row-2,col-2,first_player,&moves_left);
    if (can_capture_right)
      score_right = 1 + test_capture(me,opponent,row,col,row-1,col+1,row-2,col+2,first_player,&moves_right);
    
    moves_left = move_gen(row-2,col-2,moves_left);
    moves_right = move_gen(row-2,col+2,moves_right);
  }

  if ((!can_capture_right) && (!can_capture_left) && first_player) {
    move_t *temp_moves;
    *moves = NULL;
    D printf(" returning 0 (no captures available)\n");
    return - find_best_move(opponent,me,false,&temp_moves); 
  }  else {
    if ((can_capture_left && (!can_capture_right)) ||
	(can_capture_left && can_capture_right && (score_left > score_right))) {
      *moves = moves_left;
      D printf(" returning %d (score_left)\n",score_left);
      return score_left;
    } else {
      *moves = moves_right;
      D printf(" returning %d (score_right)\n",score_right);
      return score_right;
    }
  }
}
/*
 * 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;
}
/*
 * 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 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;
}