1

I am working on a Rubik's Cube Timer Website, (JavaScript) and it requires a scrambling algorithm. It would be easy if it was just picking random letters from an array, but there are requirements that it needs to meet. Each Letter Represents a move in the Rubik's Cube Algorithmic notation, so for example "L" would mean to move the Left side clockwise. Or "U2" would mean to move the Upper side two times, and " B' " would mean to move the Backside anticlockwise. and so on.

The thing is that there cannot be two of the same letters next to each other, and not even if they are in different directions. For example, U cannot be next to U', or U2 and so on. It must be a different letter. Sometimes, my code generates 2 of the same letter next to each other.

Here's my code:

function generateScramble() {

    //Possible Letters
    var array = new Array(" U", " D", " R", " L", " F", " B", " U\'", " D\'", " R\'", " L\'", " F\'", " B\'", " U2", " D2", " R2", " L2", " F2", " B2"); 

    var array2 = new Array(); // The Scramble.

    var rdArr = new Array(); // The Array of random numbers.

    for (var i = 0; i < 20; i++) {
        var random = Math.floor(Math.random() * array.length);
        rdArr.unshift(random);

        if (rdArr[1] - rdArr[0] == 0 ||
            rdArr[0] - rdArr[1] == 0 ||
            rdArr[1] - rdArr[0] == 6 ||
            rdArr[0] - rdArr[1] == 6 ||
            rdArr[1] - rdArr[0] == 12 ||
            rdArr[0] - rdArr[1] == 12) { // Check whether a D is next to D' or D2, or if F is next to F' or F2, R next to R' or R2, and so on
            if (random < 17) {
                random++;
            } else {
                random--;
            }
        }

        array2.push(array[random]); // Get letters in random order in the array.
    }

    var scramble = "Scramble: " + array2[0] + array2[1] + array2[2] + array2[3] + array2[4]
                                + array2[5] + array2[6] + array2[7] + array2[8] + array2[9]
                                + array2[10] + array2[11] + array2[12] + array2[13] + array2[14]
                                + array2[15] + array2[16] + array2[17] + array2[18] + array2[19];

    document.getElementById("Scramble").innerHTML = scramble; // Display the scramble

}
brokethebuildagain
  • 2,162
  • 1
  • 22
  • 44
Jakub Chaloupka
  • 177
  • 1
  • 3
  • 12
  • Please elaborate on what isn't working. For instance, a clear example with test input, the expected output, and the output your code currently gives would help a lot. "It's not working" isn't very clear on what your specific question is. – brokethebuildagain Oct 19 '17 at 17:48
  • Sorry, the thing that "Isn't Working" was that I was sometimes getting the same letters twice in a row – Jakub Chaloupka Oct 19 '17 at 18:05
  • No need to apologize, I'm just trying to help you improve your question. A clear question helps people who may be searching this site with the same problem. :) – brokethebuildagain Oct 19 '17 at 21:32
  • There's other "pruning" that needs to be taken into account in a good scrample. For example, "L2 R2 L2 R2" or "L R L R L R L R"... You need to consider commutative moves, e.g. moves on opposite faces. A good scrambler does more than just apply random moves: It makes a difficult-to-solve scramble by ensuring that the optimal solution to the scramble is at least N moves away. – benbotto Jan 02 '20 at 23:11
  • Thanks for the info! I have already abandoned the project, but when I picked it up later, I found libraries that implement Kociemba's two-phase algorithm, which I heard is / was the default – Jakub Chaloupka Jan 10 '20 at 23:22

1 Answers1

1

I think, the code could be as it:

generateScramble();

function generateScramble() {

  // Possible Letters
  var array = new Array(" U", " D", " R", " L", " F", " B")

  // Possible switches
  var switches = ["", "\'", "2"]; 

  var array2 = new Array(); // The Scramble.

  var last = ''; // Last used letter

  var random = 0;

  for (var i = 0; i < 20; i++) {
      // the following loop runs until the last one 
      // letter is another of the new one
      do {
         random = Math.floor(Math.random() * array.length);
      } while (last == array[random]) 

      // assigns the new one as the last one
      last = array[random];

      // the scramble item is the letter
      // with (or without) a switch
      var scrambleItem = array[random] + switches[parseInt(Math.random()*switches.length)];

      array2.push(scrambleItem); // Get letters in random order in the array.
  }

  var scramble = "Scramble: ";
  
  // Appends all scramble items to scramble variable
  for(i=0; i<20; i++) {
     scramble += array2[i];
  }
  
  document.getElementById("Scramble").innerHTML = scramble; // Display the scramble
}
<div id="Scramble"></div>

Hope it helps.

Andrés Morales
  • 793
  • 7
  • 20
  • It is perfect, but there is one more feature that I just realized it should have. Sorry for replying this late. The thing is that if move ind face, then the opposite face and then the first face, it cancels the first face movement. (Opposite faces are as follows: D opposite to U, L opposite to R and F opposite to B, and vice-versa), so for example “ U D U’ “ would only be a “ D “ move. And I just cannot think of any solution how to avoid it – Jakub Chaloupka Nov 09 '17 at 11:37