-4

I want to generate all permutations of 32 card deck, I represent cards as numbers 0-7, so I don´t care about color of the card. The game is very simple (divide deck into two gropus, compare two cards, add both cards to group of bigger card). I have already code this part of game, but deck is now generating randomly, and I want to look to all possibilities of cards, and make some statistics about it. How can I code this card generating? I totaly don´t know, how to code it.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Please be clear and more specific in what u ask. Also try to post what have to tried with it and ask for more clarity. Don't expect others to try out fully for you! – Sharath Jul 21 '18 at 16:47
  • 3
    "I want to generate all permutations of 32 card deck." Is your objective even possible? Bear in mind that with a regular deck **There Are More Ways To Arrange a Deck of Cards Than Atoms on Earth**. A look at [this page](http://www.murderousmaths.co.uk/cardperms.htm) may give you some hints. – Weather Vane Jul 21 '18 at 18:03
  • Yes, that´s right :( Well, I have to reduce this possibilities, by some math theory.... and, just for fun, what is best option to code this problem? permutations when sometimes array matter (different cards), sometimes not? – marcel3032 Jul 21 '18 at 18:39
  • 2
    The statistics will have to be derived from probabilty theory, not by generating all permutations of cards. It **is** possible if you use a much smaller deck, which would allow you to empirically test if the theory is correct, and if so, extend the theory to a 32 card deck. – Weather Vane Jul 21 '18 at 18:47
  • Generating all permutations of 32 cards will take at least 75 million years even if you only care about the numbers. Even if this is possible, your question will still be too broad because you're asking for a complete tutorial, which will be too long for a SO post. Start by doing some research on how to generate permutations and trying to implement it yourself. We will be happy to help if you have some trouble implementing it. – eesiraed Jul 21 '18 at 21:30

1 Answers1

1

Because I was just studying Aaron Williams 2009 paper "Loopless Generation of Multiset Permutations by Prefix Shifts", I'll contribute a version of his algorithm, which precisely solves this problem. I believe it to be faster than the standard C++ next_permutation which is usually cited for this problem, because it doesn't rely on searching the input vector for the pivot point. But more extensive benchmarking would be required to produce a definitive answer; it is quite possible that it ends up moving more data around.

Williams' implementation of the algorithm avoids data movement by storing the permutation in a linked list, which allows the "prefix shift" (rotate a prefix of the vector by one position) to be implemented by just modifying two next pointers. That makes the algorithm loopless.

My version here differs in a couple of ways.

  • First, it uses an ordinary array to store the values, which means that the shift does require a loop. On the other hand, it avoids having to implement a linked-list datatype, and many operations are faster on arrays.

  • Second, it uses suffix shifts rather than prefix shifts; in effect, it produces the reverse of each permutation (compared with Williams' implementation). I did that because it simplifies the description of the starting condition.

  • Finally, it just does one permutation step. One of the great things about Williams' algorithm is that the state of the permutation sequence can be encapsulated in a single index value (as well as the permutation itself, of course). This implementation returns the state to be provided to the next call. (Since the state variable will be 0 at the end, the return value doubles as a termination indicator.)

Here's the code:

/* Do a single permutation of v in reverse coolex order, using
 * a modification of Aaron Williams' loopless shift prefix algorithm.
 * v must have length n. It may have repeated elements; the permutations
 * generated will be unique.
 * For the first call, v must be sorted into non-descending order and the
 * third parameter must be 1. For subsequent calls, the third parameter must
 * be the return value of the previous call. When the return value is 0,
 * all permutations have been generated.
 */
unsigned multipermute_step(int* v, unsigned n, unsigned state) {
  int old_end = v[n - 1];
  unsigned pivot = state < 2 || v[state - 2] > v[state] ? state - 1 : state - 2;
  int new_end = v[pivot];
  for (; pivot < n - 1; ++pivot) v[pivot] = v[pivot + 1];
  v[pivot] = new_end;
  return new_end < old_end ? n - 1 : state - 1;
}

In case that comment was unclear, you could use the following to produce all shuffles of a deck of 4*k cards without regard to suit:

unsigned n = 4 * k;
int v[n];
for (unsigned i = 0; i < k; ++i)
  for (unsigned j = 0; j < 4; ++j)
    v[4 * i + j] = i;

unsigned state = 1;
do {
  /* process the permutation */ 
} while ((state = multipermute_step(v, n, state);

Actually trying to do that for k == 8 will take a while, since there are 32!/(4!)8 possible shuffles. That's about 2.39*1024. But I did do all the shuffles of decks of 16 cards in 0.3 seconds, and I estimate that I could have done 20 cards in half an hour.

rici
  • 234,347
  • 28
  • 237
  • 341
  • 1
    Isn't the number of permutations with 32 cards and 4 suits 32!/(4!)^8? There are 4! permutations of 4 cards with the same number, and there are 8 such groups. – eesiraed Jul 21 '18 at 21:37
  • @fei: yeah, youre right. I'll revert my change. I fooled myself with a bad benchmark. – rici Jul 21 '18 at 21:40
  • And now that I benchmarked more thoroughly, it doesn't give noticeable speedup over std::next_iteration. – rici Jul 22 '18 at 13:39