Random Move 2x2 Scrambling

A simple way to scramble a 2x2x2 Rubik's cube is to make a sequence random moves. This is not how official scrambles are done, but can get pretty close to a uniform distribution of all possible scramble states. Due to the way a 2x2 only has two layers, doing one turn on one face is equivalent (without considering the puzzle's orientation in space) to doing the same direction turn on the opposite face. For example, turning the top face clockwise moves all the pieces in relation to each other the same way turning the bottom face clockwise does. So scrambles only need to turn the top (U), right (R), and front (F) faces.

For this challenge, your program must generate a string that represents a sequence of 16 moves. A move is represented by a face, one of the letters U, R, F, followed by a direction: clockwise (empty string or space  ), counterclockwise (apostrophe '), or 180 degrees (2). The turn and direction should be chosen uniformly at random, however two consecutive moves cannot turn the same face, For example a scramble cannot contain R' R2. So the first move should have a 1/3 chance for each face, but there should be a 50/50 chance for the chosen face after the first move. Moves are separated by a space.

Example scramble:

U  F' R2 F' R' F  R  F2 U' F  R2 F  U2 F' U2 F2

• Can we output an array of moves?
– user100690
May 13, 2021 at 8:02
• @ophact since I tagged it string, I'm gonna say no.
– qwr
May 13, 2021 at 8:05
• Can we use lowercase instead of uppercase? May 13, 2021 at 8:18
• @Shaggy no. Lower case has a different meaning in cubing notation and doesn't make sense for 2x2 scrambles.
– qwr
May 13, 2021 at 8:20
• Are we allowed to put the direction before the move, e.g. F 2R 'U 'R? May 13, 2021 at 13:56

Python 3.8, 8483 82 bytes

-2 bytes thanks to dingledooper!

import random as R
print(*[(R:=c([*{*"FUR"}-{R}]))+c(" '2")for c in[R.choice]*16])


Try it online!

• interesting. how does the id trick work. edit: oh I see it has nothing to do with the id function itself
– qwr
May 13, 2021 at 8:47
• @qwr Yeah it is just a variable that is predefined and short (and hashable). In this case x=c=choice and using x instead of id would be the same length.
– ovs
May 13, 2021 at 8:50
• -1 byte May 13, 2021 at 8:59
• @dingledooper Very nice, thanks! I had the feeling the eval('...,'*16) was not quite optimal since I haven't seen it on this site before.
– ovs
May 13, 2021 at 9:04
• I found another nice trick which saves 1 byte. May 13, 2021 at 9:28

05AB1E, 19 bytes

16Fн…FRUsK… '2âΩð«?


Try it online!

16F                  # iterate 16 times:
н                 # get the first character from the value that was last on stack
…FRU             # push string "FRU"
sK           # remove the result from н
… '2       # push string " '2"
â      # cartesian product of the strings
Ω     # choose a random string from the list
ð«   # append a space
?  # print without a trailing newline


Ô - Connected uniquified a seems like a promising builtin for this challenge, but the best I could do with it is 22 bytes:

…FRU¸Þ€ΩÔ16£ε… '2Ω«}ðý


Try it online!

…FRU¸Þ                 # infinite list ["FRU", "FRU", ...
€Ω                # select a random character from each string
Ô               # remove consecutive duplicates
16£            # take the first 16 characters
ε      }    # for each of those:
… '2Ω«     # append a random char from " '2"
ðý  # join the resulting list by spaces

• Your 21 bytes doesn't work. Þ splits it into a list of characters before making it infinite, so it'll always be ["F","R","U","F","R","U",...]. The €ΩÔ are just no-ops here. I guess something like this (22 bytes) could work: …FRU₄×.rÔ16£ε… '2Ω«}ðý, although in theory the 1000×Ô could (with very small probability) result in less than 16 characters. Your 19-byter works like a charm, though. :) Jun 28, 2021 at 12:36
• @KevinCruijssen I should have paid a bit more attention to the output, but this can be fixed by cycling ["FRU"] instead of "FRU", then it works with probability 1 at 22 bytes.
– ovs
Jun 28, 2021 at 12:50

Vyxal, 352925 19 bytes

16(h‛⊍Ṁ⇧$- '2Ẋ℅¨…  Try it Online! Thanks to Lyxal for -6 bytes. 16( # Repeat 16 times (Automatically closed) h # Take first of previous ‛⊍Ṁ⇧ # Push fru, uppercased$           # Swap top two elements on stack
-          # Remove (So fru loses the first of previous iteration)
 '2     # Push  '2
Ẋ    # Cartesian product
℅   # Random choice
¨… # No idea (Can't find any docs)


My old version, 25 bytes

16(‛Ŀ¦⇧'¥≠;℅:£'2 ℅+⅛)¾Ṅ


Try it Online!

16(                   )   # 16 times
‛Ŀ¦⇧                   # Push compressed string fur, to uppercase
'  ;               # Filter by...
¥≠                # is not equal to register
℅              # Random choice
:£            # Duplicate and push to register
'2 ℅      # Random of '2
+     # Concatentated
⅛    # Push to global array
¾  # Push global array to stack
Ṅ # Join by space


I know this is a mess. Also this seems to be the only one that compresses even one of the strings.

• Try it Online! for 21 bytes (by stealing the 05ab1e answers method) May 13, 2021 at 11:45
• 19 bytes May 13, 2021 at 12:21

Charcoal, 18 bytes

Ｆ¹⁶«≔‽⁻FRUωωω‽ 2'→


Try it online! Link is to verbose version of code. Explanation:

Ｆ¹⁶«


Repeat 16 times.

≔‽⁻FRUωω


Choose a random turn that wasn't just used.

ω


Output that turn.

‽ 2'


Output a random direction.

→


Except for the last move, leave a space for the next move.

Retina, 50 bytes

$¶FRU¶ 2' (([FRU])¶.¶.*)\2$1
16}%@L.
¶

|' L..


Try it online! Explanation:

$¶FRU¶ 2'  Append the possible turns and directions. (([FRU])¶.¶.*)\2$1


Remove the turn that was made the last time.

%@L.


Pick a random turn and direction from those left.

16}


Repeat the above 16 times.

¶



Join everything together.

|' L..


Factor, 83 bytes

[ [ "UFR"""16 [ over remove random dup , "2 '"random , 32 , ] times ] ""make 2nip ]


Try it online!

One of the odd times make is shorter than sequence words (or smart combinators like append-outputs). Mainly because turning code points into strings is verbose in Factor, but make, despite being verbose itself, can do that with ease. Plus, , is much shorter than suffix or append.

Explanation:

It's a quotation (anonymous function) that takes no input and leaves a string on the data stack as output.

• [ ... ] ""make Make a string. Inside the quotation, , appends elements to a sequence. The "" is an exemplar that tells make the result should be a string.
• "UFR""" Place two strings on the stack. The first, "UFR", indicates which possible faces we can choose. The second, "", is the last face we chose, so we don't choose it twice in a row.
• 16 [ ... ] times Call a quotation 16 times.
• over remove random Pick a random face that we didn't pick last time.
• dup , Append it to our sequence without destroying it (since we need to know our last move again).
• "2 '" random , Append a random direction/move to the face.
• 32 , Append a space.
• 2nip Once make is done building the string, we still have some junk on the data stack to remove.

JavaScript (ES6),  82 81  79 bytes

f=i=>i>>10?"":"FRU"[(i=~~i-Math.random()*~-~!i)%3|0]+" '2"[i*3%3|0]+" "+f(i+64)


Try it online!

Or run a consistency check on 500,000 calls

How?

We start with $$\i=0\$$. [1]

At each iteration, we add to $$\i\$$ a random float in $$\\left[0,3\right[\$$ if $$\i=0\$$ (3 possible choices) or in $$\\left[0,2\right[\$$ if $$\i\neq 0\$$ (only 2 possible choices).

We use $$\\lfloor i\bmod 3 \rfloor\$$ as the index of the face character and $$\\lfloor (3\times i)\bmod 3 \rfloor\$$ as the index of the direction character.

After each iteration[1], we update $$\i\$$ to $$\\lfloor i+64 \rfloor\$$ in order to:

• get rid of the decimal part whose only purpose was to to choose a direction character
• make sure that we won't pick the same face character twice in a row (because $$\64 \bmod3=1\$$)
• be able to know that we've processed 16 iterations by testing if $$\i\$$ is greater than or equal to $$\1024\$$, because we add at least $$\16\times64=1024\$$ to $$\i\$$ (and at most $$\16\times65+1=1041\$$)

[1] in order to save a few bytes, we actually start with $$\i\$$ undefined, coerce it to a number at the very beginning of an iteration, and add $$\64\$$ at the end.

GolfScript, 41 bytes

16,{;'FRU'[a]-.,rand=:a" '2"3rand=32}%""+


Try It Online!

Explanation

16,{;'FRU'[a]-.,rand=:a" 'r"3rand=32}%""+
16,                                        // push the list [0..15]
{                                       // begin code block
;                                      // remove the element already in the list
'FRU'[a]-                             // remove the previous value of a from the possible choices
(initially, [a] evaluates to an empty list as a is undefined)
.,rand=                      // push the length of the string, and index the string to a
random integer in this range
:a                    // set a to this value for the next iteration
" 'r"               // push " 'r"
3rand=         // index the string to a random position
32}      // push the ASCII value for ' ', and end the block
%     // map the block over the list [0..15]
""+  // convert the resulting list of ASCII values into a string
// the string is output implicitly


(' '?16!!)<$>randomRIO(0,9*6^15-1) _?0=[""] c?n=[m:d:' ':r|m<-"RUL",m/=c,d<-" '2",r<-m?(n-1)] import System.Random  Try it online! (times out for obvious reasons, you can test it out here with 8 moves). The relevant "function" is (' '?16!!)<$>randomRIO(0,9*6^15-1), an IO String object "containing" a random sequence of moves.

As always, solving challenges in Haskell is a great idea.

How?

_?0=[""]
c?n=[m:d:' ':r|m<-"RUL",m/=c,d<-" '2",r<-m?(n-1)]


(?) is a pure function taking a character c and an integer n as input and returning the list of all valid sequences of moves of length n such that the first move is not c.

(' '?16!!)<$>randomRIO(0,9*6^15-1)  randomRIO(0,9*6^15-1) generates a random integer in the range (0,9*6^15-1); incidentally, 9*6^15 is exactly the number of valid sequences of length 16. Then with (' '?16!!)<$> we use this random integer to index into ' '?16, which is the list of valid sequences of length 16.

Japt-S, 20 19 bytes

Would be 17 if we could output the pairs reversed and in lowercase.

GÆ="RUF"kU ï" '2" ö

GÆ="RUF"kU ï" '2" ö
G                        :16
Æ                       :Map the range [0,G)
=                      :  Assign to variable U (initially 0)
"RUF"                 :  String literal
kU               :  Remove characters in U
ï" '2"        :  Cartesian product with " '2"
ö      :  Random element of resulting array
:Implicit output joined with spaces


JavaScript, 10199 91 bytes

f=(i=s=17,m=Math.random)=>--i?'URF'[s=(s>3?m()*3:s+1+m()*2)%3|0]+" '2"[m()*3|0]+' '+f(i):''


Try it online.

Explanation

We start with i and s both set to 17, then each iteration, if subtracting one from i yields a positive integer, we get the face character using a simple ternary and add a random direction character and then add a recursive call to f with the newly decremented i, and otherwise we simply return an empty string.

• doesn't make a difference for length but you should use capital letters per the spec.
– qwr
May 13, 2021 at 8:11
• @qwr oops, sorry
– user100690
May 13, 2021 at 8:13

PowerShell, 63 61 bytes

"$(1..16|%{($l='R','U','F'-ne$l|random)+("'",' ',2|random)})"  Try it online! Technically, a 60-byte solution works by using an empty string rather than a space to the second random selection; however, an error is thrown each time the empty element is selected. • nice previous check May 13, 2021 at 18:37 Jelly, 23 bytes “FUR“ '2”Wẋ⁴ŻṖḟ@"X€ɗ\ḊK  Try it online! A full program that prints a 16-long scramble. Explanation “FUR“ '2” | ["FUR"," '2"] W | Wrap in a further list ẋ⁴ | Repeat 16 times Ż | Prepend a zero ɗ\ | Reduce using the following as a dyad, keeping intermediate values: Ṗ | - Remove last item ḟ@" | - Filter out this from the next incoming copy of the list (but because of the Ṗ and ", this will only affect the FUR part) X€ | - Randomly pick a value for each Ḋ | Remove the first value (the zero) K | Separate with spaces | (Implicitly) print  J, 46 bytes 3 :0 ,'URF 2'''{~3(,3,~?@3-3:)@|+/\1+?3,15$2
)


Try it online!

Surprisingly verbose.

The only part of this I liked was the code to pick the random faces:

3|+/\1+?3,15$2  Here we create the 16 element list: 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2  Then "roll" ? for each element (so pick randomly among 0 1 2 for the first element, and among 0 1 for the second), then scan sum the result +/\, then mod by 3 3|. tacit version, also 46 [:,'URF 2'''{~3(,3,~?@3-3:)@|?@3+/\@,1+15?@$2:


But I think the explicit version is easier to read, since if you discount the boilerplate 3 :0 and ) it is effectively fewer bytes.

Raku, 54 bytes

(<F R U>.roll(*).squish Z~"2' ".comb.roll(*))[^16].put


Try it online!

• Uses squish to get rid of consecutive face repeats
• Z~ metaoperator zips the two lists, then concatenates the resulting pairs
• comb makes light work of the literal space requirement

While golfing I found other interesting Raku features that are worth highlighting:

((<F R U>.roll,{{:F<R U>,:R<F U>,:U<F R>}{$_}.roll}…*)Z~"2' ".comb.roll(*))[^16].put  Try it online! • Compact pair literal syntax within sequence generator to determine valid next cube face Alternative, 94 bytes my@m=<F R U>;((@m.roll,{%(@m.map:{$_=>(@m∖$_)}){$_}.roll}…*)Z~"2' ".comb.roll(*))[^16].put


Try it online!

• Uses set difference operator to exclude key from @m when creating key-value pairs
• can you use $_ in place of $^a? May 15, 2021 at 15:13
• also, you can use '' instead of ' ' for -1 May 15, 2021 at 15:14
• $_ is indeed equivalent – Zaid May 15, 2021 at 22:09 Java, 157 151 bytes $->{for(char i=16,c=0,j=3;i-->0;j=2)System.out.format("%c%c ",c="URF".replace(c+"","").charAt(j*=Math.random())," '2".charAt((int)(Math.random()*3)));}


Saved 6 bytes thanks to Kevin Cruijssen.

Try it online!

• You can change the (int)(Math.random()*j) to j*=Math.random() for -6 bytes. Jun 28, 2021 at 12:42
• 147 bytes Aug 2, 2021 at 7:28

Python 3.8 (pre-release), 107 106 116 108 105 104 bytes

Basic randoms

-1 bytes to @qwr's space

-1 bytes to @razetime's space

+11 bytes to randomize starting n

-8 bytes by applying new loop method and skipping ' '.join() and also defining r to randint

-3 bytes by spliting lines and removing some brackets and rearranging.

-1 byte by changing loop mathod to exec.

from random import*
r=randint;n=r(0,2)
exec("print('RFU'[(n:=n+r(1,2))%3]+choice('\\' 2'),end=' ');"*16)


Try it online!

• if you do %3 you can get rid of the -3 right
– qwr
May 13, 2021 at 8:07
• and the space before for
– qwr
May 13, 2021 at 8:08
• @qwr At the time of you commenting, I also came up with same thought, lol
– okie
May 13, 2021 at 8:09
• can the program output a scramble starting with R? it must be able to uniformly pick any of the three moves for the first move.
– qwr
May 13, 2021 at 8:09
• from random import*; for -1 May 13, 2021 at 8:20

JavaScript (Node.js), 83 bytes

f=(p='',g=s=>s[0][Math.random()*3|0],a=gURF)=>p[47]?p:f(p[0]==a?p:a+g '2+' '+p)


Try it online!

• An IIFE saves a byte: tio.run/… May 13, 2021 at 10:42
• Or call f with backticks instead of parentheses to save 4 more: tio.run/##Dcq7DoIwFIDhV@lGa5HgJTEBD2xuLiZOTZMeLsUapCctcfLdK8ufb/… Although, I don't know if we have a consensus on whether or not that's allowed. May 13, 2021 at 10:43
• And you can ditch the assignment to b completely and just call g in the recursive call to f. May 13, 2021 at 10:45
• @Shaggy Thanks for point out removing b` would save some bytes. But I'm not sure if invoke f with backticks is allowed since it seems taking extra parameters.
– tsh
May 13, 2021 at 10:58
• @Shaggy And IIFE seems a expression, which is neighter a function nor full program.
– tsh
May 13, 2021 at 11:06