I am making a simple card game, trying to shuffle a deck of cards that i made with a map.

std::map<int, std::string> theDeck;

How could I go about shuffling the items in the deck? I am having issues figuring out the algorithm. This is what I tried, but didn't work.

void shuffleDeck(std::map<int, std::string> & theDeck)
{
	srand(time(NULL));
	std::map<int, std::string>::iterator it = theDeck.begin();
	for (int i = 0; i < 51; i++)
	{
		int r = i + (rand() % (52-i)); // Random Remaining position
		int tempInt = it->first;
		std::string tempString = it->second;
		theDeck[i] = theDeck[r];
		theDeck[r] = it->second;
	}
}

Dani AI

Generated

and are right: std::map always iterates in key order, so you cannot make its traversal random. For a deck you want a sequence container and a proper shuffle. Use std::vector and std::shuffle with a real engine from <random>, then deal from the back (O(1)). See std::map is ordered by key and std::shuffle.

#include <algorithm>
#include <random>
#include <vector>

struct Card { int rank; int suit; }; // rank: 2..14, suit: 0..3
std::vector<Card> deck;
deck.reserve(52);
for (int s = 0; s < 4; ++s)
  for (int r = 2; r <= 14; ++r)
    deck.push_back({r, s});

std::mt19937 rng(std::random_device{}()); // seed once, reuse
std::shuffle(deck.begin(), deck.end(), rng);

// deal:
Card top = deck.back();
deck.pop_back();

If you like your map<int,string> for pretty names (as suggested moving to a sequence), keep it only as a lookup table and shuffle a vector of IDs. That preserves your label mapping but randomizes the draw order.

#include <algorithm>
#include <map>
#include <numeric>
#include <random>
#include <string>
#include <vector>

std::map<int, std::string> nameOf = /* 0..51 -> labels */;
std::vector<int> order(52);
std::iota(order.begin(), order.end(), 0);
std::mt19937 rng(std::random_device{}());
std::shuffle(order.begin(), order.end(), rng);

// draw a card:
int id = order.back(); order.pop_back();
std::string label = nameOf.at(id);

Tip: avoid rand/srand for shuffling; its quality and period are implementation-defined. Prefer <random> engines like std::mt19937. See std::rand notes.

Recommended Answers

All 8 Replies

The random_shuffle isn't compatible with the std::map, from all the error messages I am getting at least.

I don't think its possible to shuffle std::map because it doesn't make any sense to do that. Seems to me what you should do to represent a deck of cards is a vector of integers, so that 101 = Ace of Hearts, 102 = 2 of hearts, 201 = ace of diamonds, 301 is ace of clubs and 401 is ace of spades. Then you could use std::ramdom_shuffle() to mix them up.

Hmm, what my program does with this map is it assigns the values of 0-51 to the 52 cards and uses the string part to give the integers actual names. So i am trying to shuffle the pairs around.

Yes I realize that, but you can't shuffle std::map -- the order is fixed by the class. What I proposed was just about the same thing except use cards in the range 100-152 as Hearts, 201-252 as Diamonds, etc.

You can't shuffle map. A Quote from C++ Reference

Internally, map containers keep their elements ordered by their keys from lower to higher , therefore begin returns the element with the lowest key value in the map

so you just made a poor choice in data structure. I suggest you to use arrays of structs.

If you're using consecutive integers for the map indices, why not just use a vector?

Independently of that, it would seem to me that you could simply replace lines 8 through 11 of your code by a call to std::swap(theDeck, theDeck[r]) and delete line 4 entirely.

Well what do you suggest as the best container for a deck of cards?

Vector?
Map?
Structure?
Class?

Its a poker game.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.