Help with Card Shuffler Project

I am making a card shuffler wheel that has 52 slots and the wheel is to spin to a random open slot and then have a single card input into that slot. Process repeats until all 52 slots are full and then other stuff happens but Im focusing on the shuffling part first.

I have a code written that turns the wheel to random slots, however, the code isn't designed to not go to any taken slots.

Pls let me know if there is a better way of doing this to have all 52 slots full randomly with no duplicates. PS: wheel can only spin one direction due to physical design.

#include <Stepper.h>

#define motorSteps 3200

#define motorPin1 8
#define motorPin2 9

Stepper stepper(3200, 8,9);

int x;
int Slots[52] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52};

void setup() {

stepper.setSpeed(115);
Serial.begin(9600);

}

void loop() {
static int Times = 0;
if (Times <52) {
x=Slots[random(52)];
stepper.step(-246.15*x);
delay(2500);
Times = Times +1;

}

One suggestion: Define a 52 cell boolean array. When random takes a slot, mark it as occupied. If the slot is taken, get a new random number.

When you do this, and index it, the result is always the index plus one.
So

x=Slots[random(52)];

can just be

x=random(52) + 1;

It saves 52 bytes of essentially wasted memory, a premium on most Arduinos.

In 7 bytes of memory you can keep a flag for each of the 52 slots.

byte SlotBusy[7];

  boolean busy;
  byte slot;

  // Pick a random non-busy slot
  do
  {
    slot = random(52);
    busy = SlotBusy[slot/8] & (1 << (slot % 8));
  } while (busy);

  // Mark the slot busy
  SlotBusy[slot/8] |= (1 << (slot % 8));

If you use a Fisher Yates shuffle, you don't need to keep track of which slots have been accessed, only keep a count as you go through the slots in order from 1 to 52. At each iteration of Fisher Yates, you only need to know the slot you're swapping out, and the slot that you're swapping from (and that is just so the machine can replace it with the first card).

Hello. I need to create an array of 52 and then randomize it with no duplicates. Ex: [36 18 50 2...]

Then I need a loop to cycle through the randomized array and perform an action based on that number in the array:

So in the example, it would look at the first number (36) and the stepper motor would move to the corresponding position.

Then it would look at (18) and the stepper motor would move to the corresponding position.

How would I write this code? Im looking for detailed code regarding the randomizing of the array and the beginning of the void loop(). Thank you.

You have received solutions in others topics at same subject but I'll give you another option.

#define NUM_SLOTS 52

uint8_t data[NUM_SLOTS] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52};

void swapEntries(byte a, byte b)
{
  byte temp = data[a];
  data[a] = data[b];
  data[b] = temp;
}

void printData()
{
  for (const auto& v : data) {
    Serial.print(v);
    Serial.write(' ');
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  for (int i = 0; i < 10; i++) swapEntries(random(0, NUM_SLOTS), random(0, NUM_SLOTS)); // perform 10 swaps
  printData();
  delay(1000);
}

Yes, noticed .
Learn about the possibilities, algorithms, information handling etc. Don't think that anybody will make a fix and ready code.
Set goals within reach. Let the dreams be dreams until coming closer.....

Start by shuffling the deck and get ideas. It's not easy to create true random and handle it.

@Eddie1013, stop cross-posting. Threads merged.

Hi @johnwasser ,
I liked you solution, but I had difficulty understanding it, so I decided to simulate it.
I was in doubt with the results.
Could you please describe how your code works.
Thank you in advance for your attention.

There are two lines that do the work. The first tests a bit to see if that card has been dealt using bitwise and:

    busy = SlotBusy[slot/8] & (1 << (slot % 8));

It picks out the (slot % 8)th bit of the slot/8th byte.

And so relies on integer maths.

This sets the bit corresponding to the slot number, same maths tricks, bitwise or:

  SlotBusy[slot/8] |= (1 << (slot % 8));

And "busy" is accurate… that while loop will be quite busy near the end of the deal, when it has to stab blindly at the bytes looking for the last remaining zeros…

a7

Hello Eddie1013

Try, check and study this sketch for your project.

int numberArray[52];
constexpr int sizeofNumberArray {sizeof(numberArray) / sizeof(numberArray[0])};

void setup()
{
  Serial.begin(9600);
  Serial.println(sizeofNumberArray);
  int index2Array = 0;
  do
  {
    int randomNumber = random(1, sizeofNumberArray+1);
    int found=LOW;
    for (int n = 0; n < index2Array; n++) {if (numberArray[n] == randomNumber) found=HIGH;}
    if (found == LOW) numberArray[index2Array++] = randomNumber;
  } while (!(index2Array == sizeofNumberArray));
  for (int element : numberArray) Serial.print(element),Serial.print(" ");
  Serial.println("");
}

void loop() {}

Have a nice day and enjoy coding in C++.

Yes. Why reinvent the wheel? This is one problem that has been solved!

Straight off wikipedia with no help from chatGPT. It initialises numberArray with a shuflfe of numbers 0..51:

// Fisher Yates initialise / shuffle. oh, Knuth.
void deal()
{
  for (unsigned char tt = 0; tt < 52; tt++) {
    unsigned char card = random(0, tt + 1);

    numberArray[tt] = numberArray[card];
    numberArray[card] = tt;
  }
}

And is never even a bit busy looking for holes or madly swapping enough times so the "deck" is random. 52 calls to random().

a7

Rather than shuffling the array and then picking from it sequentially, another option is to fill the array sequentially and pick from it randomly. Moving the picked option to the end of the array and shortening the array separates the values into those available for picking and those already picked.

byte Cards[52];
byte AvailableCards = 0;
void resetDeck()
{
  for (int i = 0; i < 52; i++)
    Cards[i] = i;
  AvailableCards = 52;
}

byte dealOne()
{
  if (AvailableCards == 0)
    resetDeck();

  // Pick one of the remaining available cards.
  byte chosenPlace = random(AvailableCards);
  byte chosenCard = Cards[chosenPlace];

  // Swap it with the last available card
  Cards[chosenPlace] = Cards[AvailableCards - 1];
  Cards[AvailableCards - 1] = chosenCard;

  // Make it no-longer-available
  AvailableCards--;

  return chosenCard;
}

But then... isn't the last pick limited in possible values? Unless I misunderstand. For example near the end of the process, you are picking something to go in slot 2, but it can only be 1 or 0 (unpicked segment).

By the time you get down to AvailableCards == 2, the first two slots have likely been picked before and swapped with whatever value happened to be last in the remaining array. Possibly multiple times. It is always a random choice evenly distributed across all of the numbers that have not yet been picked.

When you get to AvailableCards == 1 you will always get element 0 which will contain the only value that has not been picked. That will be swapped with element 0 and AvailbleCards will be decremented to 0. There will always be a last card. That last card depends on when and how many times the random choice came up 0 in the 51 previous choices.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.