Search code examples
c++listsetemplace

add random element of a set to a list and remove it from original set


I have a set of strings and want to add random elements of that set to a list (e.g. distribute poker cards to different players)

I've tried the following:

std::set<std::string> remaining_cards;
std::vector<std::set<std::string>> player_cards;

int random_number;
for (int i = 0; i < number_of_players; ++i) 
{
    random_number = 2;  // for simplicity let's assume the random number is always 2
    auto it = remaining_cards.cbegin();
    std::advance(it, random_number);
    player_cards.emplace_back(remaining_cards.cbegin(), it);  // get one element
    remaining_cards.erase(it);  // remove distributed card from deck
}

Why do I end up with the same card for all players even though I remove the one that got distributed in the last line from the deck with erase?


Solution

  • I'm not sure why you are using std::set... probably because it sorts the cards automatically. I would use std::vector and sort manually (std::sort).

    I have to fill in some blanks on what you are trying to do in the code, as you didn't post a working, complete example.

    I would suggest using encapsulation and moving the drawn cards instead of copying before deletion. E.g.

    #include <random>
    #include <string>
    #include <set>
    #include <vector>
    #include <numeric>
    
    class Random {
    private:
        std::default_random_engine generator{};
    public:
        int operator()(int maxValue) { return generator() % maxValue; }
    };
    
    class Card {
    private:
        std::string name{};
    public:
        Card() : name{} {}
        Card& operator= (int i) {
            name = std::to_string(i);
            return *this;
        }
        friend bool operator<(Card const& lhs, Card const& rhs) {
            return lhs.name < rhs.name; // or some other sorting.
        }
    };
    
    class Player {
    private: 
        std::set<Card> cards{};
    public:
        void AddCard(Card&& card) noexcept {
            cards.emplace(std::move(card));
        }
    };
    
    int main() {
        //fill the deck
        std::vector<Card> deck(42); // instead of remaining cards... why would this be a set?
        std::iota(std::begin(deck), std::end(deck), 1); // fill 1 to 42
    
        Random random{};
    
        std::vector<Player> players(4);
        while (deck.size() > 0) { // distribute the whole deck.
            for (auto& player : players) {
                if (deck.empty()) break; // if cards in desck is not equaly dividable between players
                auto randIdx = random(deck.size());
                player.AddCard(std::move(deck[randIdx]));  // move one card
                deck.erase(std::next(std::begin(deck), randIdx));  // and remove it from deck
            }
        }
    }