How do I print a shuffled order of strings that never repeat? [SOLVED]

I'm trying to make a scramble generator for the rubik's cube, every letter corresponds to a move on the cube, but I don't want that two moves get printed next to each other, for example " R R U U2 L' " because that would make quite inefficient that scramble. I'll paste part of the code down below:

char a0[] = "R ";
char a1[] = "L' ";
char a2[] = "B' ";
char a3[] = "D2 ";
char a4[] = "F ";
char a5[] = "U2 ";
int moveA;

    for (int i=0; i < 6; i++)
    {
      moveA = random(0,5);
      if (moveA == 0)
        Serial.print(a0);
      else if (moveA == 1)
        Serial.print(a1);
      else if (moveA == 2)
        Serial.print(a2);
      else if (moveA == 3)
        Serial.print(a3);
      else if (moveA == 4)
        Serial.print(a4);
      else if (moveA == 5)
        Serial.print(a5);
      delay(200);

The output is usually something like

B' F D2 D2 R B' 
F2 D' D' F2 R2 R2 

The first thing to fix is the random number

random(0, 5);

will return a value between 0 and 4, not between 0 and 5

Have you got a list of code pairs that must not appear in adjacent moves or can you provide an algorithm that given 2 codes can return a true/false value indicating whether they are allowed ?

R should not be next to R, L with L, U with U, and so on...
I have no idea on how to explain this on my code :\

sorry for the edit, I did too much confusion

if you don't want to repeat the last one you printed, one way is to not be able to select it when you pick a random position.

  • define your array of moves
  • shuffle that array so that you get some initial randomisation
  • repeat :
    • pick one that is not the last one in the array
    • swap it with the last position
const char * moves[] = {"M1", "M2", "M3", "M4", "M5"};
const byte count = sizeof moves / sizeof * moves;

// Fisher–Yates shuffle
void shuffleArray(const char ** a, const size_t size) {
  for (size_t i = size - 1; i > 0; --i) {
    size_t r = random(0, i + 1); // generate rand numbers from 0 to i
    const char * tmpSwap = a[i];
    a[i] = a[r];
    a[r] = tmpSwap;
  }
}

byte nextMove() {
  byte moveIndex = random(0, count - 1);  // pick one that is not the last one
  const char * tmp = moves[count - 1];    // exchange it with the last position
  moves[count - 1] = moves[moveIndex];
  moves[moveIndex] = tmp;
  return count - 1;                       // return the last position
}

void setup() {
  randomSeed(analogRead(A0));
  shuffleArray(moves, count); // get initial randomization
  Serial.begin(115200);

  // generate 100 moves
  for (size_t n = 0; n < 100; n++) {
    Serial.print(moves[nextMove()]); Serial.write(' ');
    if ((n + 1) % 10 == 0) Serial.println();    // new line every 10 print
  }
}

void loop() {}

R should not be next to R or L since "R R" is the same as "R2" and "R L" would result in no change.

For each move, pick an axis (RL, UD, or FB) that is different from the previous axis. Then pick a random move on that axis:
RL -> R, R2, R', L, L2, L'
UD -> U, U2, U', D, D2, D'
FB -> F, F2, F', B, B2, B'

See also:

ah got it.

➜ ignore my code then, it's definitely not doing that !

I believe there is swap function available

but it would do the same, won't it?

yes just in 1 line

in one "visible" line :slight_smile:

Oops. I got that bit wrong. The reason you don't want to do "R L" is that if you then do R' it will undo the "R". The scramble will be two steps shorter than expected. By switching axis each time (RL, UD, FB) there is no way for a single move to undo a previous move.

Hi, thank you so much for your help! I modified quite a lot my code and went for a different way. here's my result:

#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

char *RL[] = {
"R ", "R' ", "R2 ", "L ", "L' ", "L2 ",
};

char *UD[] = {
"U ", "U' ", "U2 ", "D ", "D' ", "D2 ", 
};

char *FB[] = {
"F ", "F' ", "F2 ", "B ", "B' ", "B2 ",
};
  lcd.begin(16, 2);
  Serial.println("");
  randomSeed(analogRead(0));
  for (int i=0; i < 2; i++)
  {
    for (int i=0; i < 2; i++)
    {
      delay(20);
      lcd.print(RL[random(0,6)]);
      delay(20);
      lcd.print(UD[random(0,6)]);
      delay(20);
      lcd.print(FB[random(0,6)]);
    }
    lcd.setCursor(0,1);
    for (int i=0; i < 2; i++)
    {
      delay(20);
      lcd.print(UD[random(0,6)]);
      delay(20);
      lcd.print(FB[random(0,6)]);
      delay(20);
      lcd.print(RL[random(0,6)]);
    }
    delay(10500);
    lcd.clear();
  }

those 3 arrays would be better declared as const char *

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