Wrote some code to pick random cards from an expanding number of decks. Only "opening" a new deck when needed. If you ask for 13 random diamonds and 13 random spades then it will only use one deck. But if you request 14 random diamonds or 5 random kings then it will start using a second deck.

int MAX_DECKS = 10;
int16_t get_from_decks(bool *decks, int search_rank, int search_suit)
{
    int start_rank = search_rank == -1 ? rand()%13 : search_rank;
    int start_suit = search_suit == -1 ? rand()%4 : search_suit;
    int rank, suit;
    int deck = 0;
    bool found = false;
    
    while(deck < MAX_DECKS && !found) {
        for(int rank_offset=0;
                rank_offset < (search_rank == -1 ? 13 : 1) && !found;
                rank_offset++) {
            for(int suit_offset=0;
                    suit_offset < (search_suit == -1 ? 4 : 1) && !found;
                    suit_offset++) {
                
                rank = (start_rank + rank_offset) % 13;
                suit = (start_suit + suit_offset) % 4;
                int idx = rank + suit * 13 + deck * 52;
                
                if(decks[idx]) {
                    decks[idx] = false;
                    found = true;
                }
            }
        }
        
        deck++;
    }
    
    return rank + suit * 13;
}

The algorithm will always try to empty the previous decks even if new ones have been opened. So if the first deck has 1 remaining club, the second deck has 10 clubs and you request a random club then it will always return the last club from deck 1.

If you go past MAX_DECKS then the code returns cards that match the search criteria but without taking into account decks (so five random hearts could come up 5 aces).

The code isn't high performance. It just does a brute force search for a free card matching the criteria. A search three and/or meta data about remaining cards in the deck would make it faster but I only need it to process a limited set of cards (and only once during a file load).

Demo of function:

int most_copies(int *array) {
    int copies = 0;
    for(int i=0; array[i] != -1; i++) {
        int count = 1;
        for(int a=i+1; array[a] != -1; a++) {
            if(array[i] == array[a]) {
                count++;
            }
        }
        copies = count > copies ? count : copies;
    }
    return copies;
}

int main (int argc, char const *argv[])
{
    bool* decks = (bool*)malloc(sizeof(bool)*52*MAX_DECKS);
    memset(decks, 1, sizeof(bool)*52*MAX_DECKS);
    
    int *created_cards = (int*)malloc(sizeof(int)*100);
    memset(created_cards, -1, sizeof(int)*100);
    
    // Get 52 random cards (full deck)
    for(int i=0; i<52; i++) {
        created_cards[i] = get_from_decks(decks, -1, -1);
    }
    printf("Decks for 52 cards: %d\n", most_copies(created_cards));
    
    // Get 60 random cards (full deck + 8 cards)
    memset(decks, 1, sizeof(bool)*52*MAX_DECKS);
    memset(created_cards, -1, sizeof(int)*100);
    for(int i=0; i<60; i++) {
        created_cards[i] = get_from_decks(decks, -1, -1);
    }
    printf("Decks for 60 cards: %d\n", most_copies(created_cards));
    
    // Get 5 aces (2 decks):
    memset(decks, 1, sizeof(bool)*52*MAX_DECKS);
    memset(created_cards, -1, sizeof(int)*100);
    for(int i=0; i<5; i++) {
        created_cards[i] = get_from_decks(decks, 0, -1);
    }
    printf("Decks for 5 aces: %d\n", most_copies(created_cards));   
    
    // Get 27 diamonds (3 decks):
    memset(decks, 1, sizeof(bool)*52*MAX_DECKS);
    memset(created_cards, -1, sizeof(int)*100);
    for(int i=0; i<27; i++) {
        created_cards[i] = get_from_decks(decks, -1, 0);
    }
    printf("Decks for 27 diamonds: %d\n", most_copies(created_cards));  
    
    return 0;
}

Output:

Decks for 52 cards: 1
Decks for 60 cards: 2
Decks for 5 aces: 2
Decks for 27 diamonds: 3