# A really short Javascript scrambler function



## molarmanful (May 30, 2015)

I recently got into code-golfing, and I decided to JS-golf a 3x3 scrambler. The Gist is at https://gist.github.com/molarmanful/2f299ae96f6120cf5283. What do you guys think? Any ideas for saving more bytes?


----------



## Lucas Garron (May 30, 2015)

molarmanful said:


> What do you guys think?



I think we've got enough bad small scramblers. ;-)


----------



## rokicki (May 30, 2015)

molarmanful said:


> I recently got into code-golfing, and I decided to JS-golf a 3x3 scrambler. The Gist is at https://gist.github.com/molarmanful/2f299ae96f6120cf5283. What do you guys think? Any ideas for saving more bytes?



Code golf is great fun! How many bytes would you need to *add* to make it be a proper random-state
scrambler with reasonably short result sequences?


----------



## Lucas Garron (May 30, 2015)

rokicki said:


> Code golf is great fun! How many bytes would you need to *add* to make it be a proper random-state
> scrambler with reasonably short result sequences?



This is actually a great question.

My first instinct is to decompose the cube into Thistlethwaite-like steps, and store a table to randomize each subgroup in order. Unfortunately, I'm not aware of a decomposition that's likely to lead to something short enough that a scrambler would be okay using it instead of our current high-quality scrambles (say, under 30 moves).


----------



## qqwref (May 30, 2015)

```
<script>r=Math.random;for(c=b=j=25;j;c+b-5|c-m&&b-m?document.write("URFBLD"[j--,c=b,b=m]+" 2'"[0|r()*3]+" "):0)m=0|r()*6</script>
```


----------



## rokicki (May 30, 2015)

Lucas Garron said:


> This is actually a great question.
> 
> My first instinct is to decompose the cube into Thistlethwaite-like steps, and store a table to randomize each subgroup in order. Unfortunately, I'm not aware of a decomposition that's likely to lead to something short enough that a scrambler would be okay using it instead of our current high-quality scrambles (say, under 30 moves).



Machines are fast enough these days so you can do a full two-phase solver
including generating a partial table for each phase and get results pretty
quickly. Quick enough? Maybe. Is a few seconds fast enough? You don't
really need that much of either table to do a reasonable job, as Kociemba
proved with his Atari ST solver.

And two-phase would simplify things over Thistlethwaite, as well as
guarantee good solutions.

You're still probably talking a kilobyte of compressed code, though.

Maybe I should start another "short cube solving contest" with slightly
different metrics to see what people can come up with.


----------



## Calode (May 30, 2015)

I had a go at it, learned a few things from you. My attempt (129 bytes): 

```
function(){a=l=[];r=Math.random;while(l++<25)a.push('RLUDFB'.replace(a[l-2],'')[0|r()*5]+["'",2,''][0|r()*3]);return a.join(' ')}
```

Or expanded: 

```
function(){
    a=l=[];
    r=Math.random;
    while(l++<25)
        a.push('RLUDFB'.replace(a[l-2],'')[0|r()*5]+["'",2,''][0|r()*3]);
    return a.join(' ')
}
```

I love your clever use of taking advantage of the update part of the for loop to add onto the generated move. Instead, I took an approach where I remove the previous move of the possible moves to generate. I still feel like I could make it smaller.

edit: just realized my code for checking the previous move doesn't even work. I fixed it and now it's 132 characters:

```
function(){a=p=l=[];r=Math.random;while(l++<25)a.push((p="RLUDFB".replace(p,'')[0|r()*5])+["'",2,''][0|r()*3]);return a.join(' ')}()
```

All I did was add p and set p to the previous move.


----------



## molarmanful (May 30, 2015)

Calode said:


> I had a go at it, learned a few things from you. My attempt (129 bytes):
> 
> ```
> function(){a=l=[];r=Math.random;while(l++<25)a.push('RLUDFB'.replace(a[l-2],'')[0|r()*5]+["'",2,''][0|r()*3]);return a.join(' ')}
> ...



Nice! Little tip: you can save even more bytes by using for instead of while loops. 

As of this post, the byte count for my Gist is at 127.


----------



## Calode (May 30, 2015)

I realized as I tried optimizing it more (getting rid of .push, now 129 bytes), that I keep getting closer to your code. 
At first, I tried using Array.map and get rid of the loops but as I tried I found out that it was hard so I ended up using a while loop and it kept getting closer to yours.


----------



## samuelqwe (May 30, 2015)

I've made an example page at this link if people want to test it out:

https://jsfiddle.net/sz8jw62t/2/


----------



## biscuit (May 30, 2015)

samuelqwe said:


> I've made an example page at this link if people want to test it out:
> 
> https://jsfiddle.net/sz8jw62t/2/



pretty good but with your code it allows "useless" moves. Here is a scramble generated with your code. U R2 D' L' D' L R D L R2 F' U2 D B R' B2 F2 B2 F D2 F D2 R2 L' U2

As you can see there is a B2 F2 B2 which is a bad thing.


----------



## molarmanful (May 30, 2015)

qqwref said:


> ```
> <script>r=Math.random;for(c=b=j=25;j;c+b-5|c-m&&b-m?document.write("URFBLD"[j--,c=b,b=m]+" 2'"[0|r()*3]+" "):0)m=0|r()*6</script>
> ```



Wait a sec... Not counting the script tags, you just wrote a 112-byte scrambler. Nice! I'll add this to the Gist in a separate file.


----------



## molarmanful (May 30, 2015)

biscuit said:


> pretty good but with your code it allows "useless" moves. Here is a scramble generated with your code. U R2 D' L' D' L R D L R2 F' U2 D B R' B2 F2 B2 F D2 F D2 R2 L' U2
> 
> As you can see there is a B2 F2 B2 which is a bad thing.



Oh, I completely forgot to take that into account! Well, back to coding...


----------



## biscuit (May 30, 2015)

The set objective for this code golf is to output a scramble right?

<!DOCTYPEhtml><body><p>DRL2BD2F2R2B2F2D'UBD'F2UF'U'D'FDB'F2R2L'R'</P></body> (76 characters by my count)

No? Ok


----------



## samuelqwe (May 30, 2015)

biscuit said:


> pretty good but with your code it allows "useless" moves. Here is a scramble generated with your code. U R2 D' L' D' L R D L R2 F' U2 D B R' B2 F2 B2 F D2 F D2 R2 L' U2
> 
> As you can see there is a B2 F2 B2 which is a bad thing.



I didn't make the scrambler, I just made an example out of the existing one found in this thread.


----------



## samuelqwe (May 30, 2015)

biscuit said:


> The set objective for this code golf is to output a scramble right?
> 
> <!DOCTYPEhtml><body><p>DRL2BD2F2R2B2F2D'UBD'F2UF'U'D'FDB'F2R2L'R'</P></body> (76 characters by my count)
> 
> No? Ok



The only problem here is, it's not "Random".


----------



## Calode (May 30, 2015)

samuelqwe said:


> The only problem here is, it's not "Random".



Technically it is. http://xkcd.com/221/


----------



## qqwref (May 30, 2015)

molarmanful said:


> Wait a sec... Not counting the script tags, you just wrote a 112-byte scrambler. Nice! I'll add this to the Gist in a separate file.


Oh, I didn't write that just now, that's a solution from the previous thread (from 2010). I have that entire thing saved as a working .htm file, and both Firefox and Chrome are nice enough to run it even without <html>/<head>/<body> tags.


----------



## Stefan (May 31, 2015)

biscuit said:


> The set objective for this code golf is to output a scramble right?
> 
> <!DOCTYPEhtml><body><p>DRL2BD2F2R2B2F2D'UBD'F2UF'U'D'FDB'F2R2L'R'</P></body> (76 characters by my count)
> 
> No? Ok



Beat you by one byte!


----------



## biscuit (May 31, 2015)

Stefan said:


> Beat you by one byte!




arg... I mean the scramble was randomly generated. If I could find a smaller (random) scramble would I win?


----------



## molarmanful (May 31, 2015)

biscuit said:


> arg... I mean the scramble was randomly generated. If I could find a smaller (random) scramble would I win?



Well, if you enter a submission that's short enough, then I can put it on my gist.



Calode said:


> I had a go at it, learned a few things from you. My attempt (129 bytes):
> 
> ```
> function(){a=l=[];r=Math.random;while(l++<25)a.push('RLUDFB'.replace(a[l-2],'')[0|r()*5]+["'",2,''][0|r()*3]);return a.join(' ')}
> ...



Oh yeah, I put your code on the Gist. I also have a suggested modification that puts you at 127 bytes:


```
function s(){for(a=p=l=[],r=Math.random;l++<25;)a.push(p="RLUDFB".replace(p,'')[0|r()*5]+["'",2,''][0|r()*3]);return a.join(' ')}
```

- Changed while to for (no bytes *directly* saved)
- Took out parentheses between the ( and the p and between the ] and + (2 bytes)
- Put variable declarations inside for loop (1 byte)
This isn't the code I have on the Gist, but let me know if you want me to switch you to this version.


----------



## qqwref (May 31, 2015)

If we're allowing static 25-move scrambles...


```
"F R U B L ".repeat(5)
```


----------



## molarmanful (May 31, 2015)

Okay, I lowered my code's byte count to 112 bytes!!! Sadly, my edits make the code only compatible with ES6+. The source is on the gist, but I'll put it here for reference:


```
_=>{for(a=s=y=r='',x=Math.random;a++<25;s+=r+["'",2,''][0|x(y=r)*3]+' ')for(;r==y;r='RLUDFB'[0|x()*6]);return s}
```


----------



## Calode (Jun 1, 2015)

molarmanful said:


> Oh yeah, I put your code on the Gist. I also have a suggested modification that puts you at 127 bytes:
> 
> 
> ```
> ...



Won't taking out the parentheses assign p to "RLUDFB".replace(p,'')[0|r()*5] *+* ["'",2,''][0|r()*3] rather than just the first part like I want?

Just tested it: yes. It did what I didn't want it to. 
I wanted it to evaluate p = the move, then add the move and the ' , 2 or nothing.




molarmanful said:


> Okay, I lowered my code's byte count to 112 bytes!!! Sadly, my edits make the code only compatible with ES6+. The source is on the gist, but I'll put it here for reference:
> 
> 
> ```
> ...



I was going to try making one with io.js but couldn't figure out how to run it. And then learning the tricks would take some time. I felt a bit lazy. Is it just replacing function with arrow notation that you did?

edit: I don't know how to use forums so until someone posts again, I'll keep editing this post


```
function(){a=p=l=[];r=Math.random;while(l++<25)a.push((p='RLUDFB'.replace(p,'')[0|r()*5])+" 2'"[0|r()*3]);return a.join(' ')}
```

I brought it down to 125!! 

and 124 if you replace while with for

```
function(){for(a=p=l=[],r=Math.random;l++<25;)a.push((p='RLUDFB'.replace(p,'')[0|r()*5])+" '2"[0|r()*3]);return a.join(' ')}
```

basically: replacing the ["'",2,''] with " '2" to remove 4 bytes


----------



## molarmanful (Jun 1, 2015)

Calode said:


> Won't taking out the parentheses assign p to "RLUDFB".replace(p,'')[0|r()*5] *+* ["'",2,''][0|r()*3] rather than just the first part like I want?
> 
> Just tested it: yes. It did what I didn't want it to.
> I wanted it to evaluate p = the move, then add the move and the ' , 2 or nothing.
> ...



For me, I switched from using an array to just using a string to do all the work. That eliminated the need to use .join(). Then I added the arrow function, which cut out the need to write out 'function.'


----------



## biscuit (Jun 1, 2015)

qqwref said:


> If we're allowing static 25-move scrambles...
> 
> 
> ```
> ...



We are saying random scrambles. To me that does not seem random because it was not completely randomly generated.


----------



## StachuK1992 (Jun 1, 2015)

biscuit said:


> We are saying random scrambles. To me that does not seem random because it was not completely randomly generated.


Neither are yours (or anyone's, truly, right?).

That's said, this is interesting so let's keep this to actual solutions and not a bunch of useless circle-jerking.


----------



## biscuit (Jun 2, 2015)

StachuK1992 said:


> Neither are yours (or anyone's, truly, right?).
> 
> That's said, this is interesting so let's keep this to actual solutions and not a bunch of useless circle-jerking.



Actually it is random because I used a random scrambler to pick the entire set of moves. But you're right it's pointless and unproductive so let's just move on.


----------



## United Thought (Jun 6, 2015)

My 4 minute attempt in Python:

123 bytes;
93 chars no spaces;
117 chars spaces;

Really easy to write and follow, although uses unorthodox notation; U+ = U; U- = U':



```
import random as r
c = 'UDLRFB'
m = '-2+'
s = ""
for i in range(0, 25):
    s += (r.choice(c) + r.choice(m) + " ")
print(s)
```

output:

```
L2 U- R- D- F+ B- B2 D- F- R2 R+ F- R- U+ U+ U+ R+ U+ B2 B- B2 B- U- U2 U+
```


----------



## Calode (Jun 6, 2015)

We're doing python? Sweet!


```
import random as r;' '.join([('UDRLFB'[r.randint(0,5)]+" '2"[r.randint(0,2)]) for i in range(25)])
```

Exactly as it is, it is 98 bytes. It does not however prevent the same moves being consecutive. I'll be working on that now.

Got yours down to 83 bytes (82 characters, the new line is required before the for statement apparently): 


```
import random as r;s="";
for i in range(25):s+=(r.choice('UDRLFB')+r.choice('-2+')+" ");
```

Just removed the declarations of c and m and moved them inside of the choices.

A simple edit of yours brings it up to to 102 bytes but keeps track of previous move:


```
import random as r;s="";
for i in range(25):p=r.choice('UDRLFB'.replace(p,''));s+=p+r.choice('-2+')+' ';
```

Where p is the previous move. Replaces the previous move with '' removes the previous move as a possible choice.

Used choice for mine and brought it down to 86 bytes: 


```
import random as r;' '.join([(r.choice('UDRLFB')+r.choice(" '2")) for i in range(25)])
```


----------



## United Thought (Jun 6, 2015)

Calode said:


> We're doing python? Sweet!
> 
> 
> ```
> ...



Ahh, thanks alot, it has been a while sine I have been programming, that edit is nice, I was about to start work on the exact same thing but qqTimer LSLL. 
BTW, does having a newline increase the size of the file?


----------



## Calode (Jun 6, 2015)

United Thought said:


> Ahh, thanks alot, it has been a while sine I have been programming, that edit is nice, I was about to start work on the exact same thing but qqTimer LSLL.
> BTW, does having a newline increase the size of the file?



It does increase the file size. /n (newline) is an extra byte.


----------



## United Thought (Jun 6, 2015)

Calode said:


> It does increase the file size. /n (newline) is an extra byte.



Thanks, I thought so, I wonder what the smallest possible random-state scrambler that could be written is..


----------



## Calode (Jun 6, 2015)

United Thought said:


> Thanks, I thought so, I wonder what the smallest possible random-state scrambler that could be written is..



The first hurdle would be figuring out how to make a random state scrambler.


----------



## molarmanful (Jun 6, 2015)

Calode said:


> The first hurdle would be figuring out how to make a random state scrambler.


I actually have almost no idea how random-state scramblers work, other than you generate a 25-move scramble randomly, then solve it in fewer moves.


----------



## Stefan (Jun 6, 2015)

molarmanful said:


> I actually have a̶l̶m̶o̶s̶t̶ no idea how random-state scramblers work,̶ ̶o̶t̶h̶e̶r̶ ̶t̶h̶a̶n̶ ̶y̶o̶u̶ ̶g̶e̶n̶e̶r̶a̶t̶e̶ ̶a̶ ̶2̶5̶-̶m̶o̶v̶e̶ ̶s̶c̶r̶a̶m̶b̶l̶e̶ ̶r̶a̶n̶d̶o̶m̶l̶y̶,̶ ̶t̶h̶e̶n̶ ̶s̶o̶l̶v̶e̶ ̶i̶t̶ ̶i̶n̶ ̶f̶e̶w̶e̶r̶ ̶m̶o̶v̶e̶s̶.̶



Fixed that for you.

Your idea would produce poor quality scrambles and hide the fact that they're poor quality! That's possibly the worst scrambler idea ever.



molarmanful said:


> I recently got into code-golfing, and I decided to JS-golf a 3x3 scrambler. The Gist is at https://gist.github.com/molarmanful/2f299ae96f6120cf5283. What do you guys think? Any ideas for saving more bytes?



I just ran it, first scramble contained L' R L' R', which trivially cancels to L2.

Try again.

Same goes for everybody else who doesn't prevent such stuff. Please don't try to weaken what has been the random-moves standard for many years.



Calode said:


> ```
> import random as r;s="";
> for i in range(25):s+=(r.choice('UDRLFB')+r.choice('-2+')+" ");
> ```



Um... end-of-line semi-colons?

Also:
for _ in' '*25
c=__import__('random').choice

Here's 65 in a few versions:

```
>>> import random;''.join(map(random.choice,['UDLRFB'," 2'",' ']*25))
"F' R  B' B' R  U' U2 U' B' D  B2 R  U  F  B' L  F2 U' D  D2 R' L' D2 B  R' "

>>> import random as r;''.join(map(r.choice,['UDLRFB'," 2'",' ']*25))
"U' B2 F  U' L2 D' R  B2 B' F  R  B  L2 B  U2 R' R' L  B2 D2 B2 D' D' R' U  "

>>> ''.join(map(__import__('random').choice,['UDLRFB'," 2'",' ']*25))
"D' U2 U' R  D2 U' U2 L' R  F' U2 F' B' R2 U  F' D  F  B' F' R2 B' F2 F2 R  "
```

But remember this is invalid anyway because of the trivial cancellations.


----------



## Jakube (Jun 6, 2015)

Stefan said:


> Here's 67 in a few versions:
> 
> ```
> import random;s=''.join(map(random.choice,['UDLRFB'," 2'",' ']*25))
> ...



You can save one char by importing everything from the random-module. 


```
from random import*;s=''.join(map(choice,['UDLRFB'," 2'",' ']*25))
```


----------



## Stefan (Jun 6, 2015)

Darn. I've been stackoverflowing too much recently, and they don't appreciate import* there


----------



## molarmanful (Jun 7, 2015)

Stefan said:


> Darn. I've been stackoverflowing too much recently, and they don't appreciate import* there


Ha lol


----------



## qqwref (Jun 7, 2015)

I don't like this thread as much as the other code golf one 

For clarity, here are the rules (as far as I know):
- Random moves: Generate a sequence of 25 moves in standard notation. Turning the same face twice is not allowed. Turning the same face twice with only an opposite-face turn between the two is not allowed. 
- Random state: Choose a random solvable position on the cube and output a sequence of moves in standard notation that solves it.


----------



## molarmanful (Jun 8, 2015)

qqwref said:


> I don't like this thread as much as the other code golf one
> 
> For clarity, here are the rules (as far as I know):
> - Random moves: Generate a sequence of 25 moves in standard notation. Turning the same face twice is not allowed. Turning the same face twice with only an opposite-face turn between the two is not allowed.
> - Random state: Choose a random solvable position on the cube and output a sequence of moves in standard notation that solves it.



The rules are also listed in the Gist.


----------



## Stefan (Jun 8, 2015)

molarmanful said:


> The rules are also listed in the Gist.



Right, please fix them there already. Or at the very very least, *warn* people instead of encouraging them to use the flawed programs.


----------



## qqwref (Jun 8, 2015)

molarmanful said:


> The rules are also listed in the Gist.


That may be true, but considering most of this thread is people posting and helping with programs that clearly don't generate working scrambles, they're definitely not being followed or understood.


----------



## molarmanful (Jun 8, 2015)

qqwref said:


> That may be true, but considering most of this thread is people posting and helping with programs that clearly don't generate working scrambles, they're definitely not being followed or understood.



Yeah, I added the rules _as a result_ of seeing *not-really-functional* scramblers. The entries in the Gist are all tested and work. However, there are only 3 entries, and I'd like more to be put in... Anyway, I did add a warning. It's all on the Gist.

I also updated my scrambler: It's not wrapped in a function anymore, meaning that it works in browser Javascript, and I used console.log as an output. I ended up with 113 bytes, which isn't too bad of a byte raise.


```
for(a=s=y=r='',x=Math.random;a++<25;s+=r+["'",2,''][0|x(y=r)*3]+' ')for(;r==y;r='RLUDFB'[0|x()*6]);console.log(s)
```


----------



## Stefan (Jun 8, 2015)

molarmanful said:


> Yeah, I added the rules _as a result_ of seeing *not-really-functional* scramblers.



You act like you're some kind of savior from bad scramblers when in fact *you're one of those bad people*, and worse than most, as you're so actively advocating bad scrambling. How many more times does it need to be pointed out to you that *your rules are bad* and that even *your own scrambler is bad*?



molarmanful said:


> ```
> for(a=s=y=r='',x=Math.random;a++<25;s+=r+["'",2,''][0|x(y=r)*3]+' ')for(;r==y;r='RLUDFB'[0|x()*6]);console.log(s)
> ```



Just tried it, got these:

L' B' U' L' B U' B' D2 L2 D U' B' R *U2 D U'* F L F' R U2 L' F' L B2
B' F2 L2 D U B2 *F' B' F* D B D2 F' R D2 L B' D B2 U' L2 F B' U D


----------



## mDiPalma (Jun 8, 2015)

what is God's number if you require a different axis for each move? how much more than 20? 

i know the mainstream superflip alg has some parallel moves.

if you could get a bound on that, it might be much more efficient (and good) in ur codes


----------



## molarmanful (Jun 8, 2015)

Stefan said:


> You act like you're some kind of savior from bad scramblers when in fact *you're one of those bad people*, and worse than most, as you're so actively advocating bad scrambling. How many more times does it need to be pointed out to you that *your rules are bad* and that even *your own scrambler is bad*?
> 
> 
> 
> ...



Okay, chill. I see what you mean. I wasn't trying to act like a savior, and I sure never said my rules OR scrambler was good...

But thanks for the words of encouragement, though. Love it  ! It's great to have people criticizing me; it's a great chance for me to improve. Keep it up, Stefan! I sure will need it.

Anyway, I did take the same-axis problem into account. I decided to disregard it (for now) because I wasn't too sure of a way to solve the problem _efficiently_. So for the sake of code golf, I decided to keep away from that issue until either I figured it out. However, thanks to you, Stefan, I have decided to work on the solution to the same-axis problem. I'll probably have the solution sometime soon? Not too sure. But I'm working on it.


----------



## qqwref (Jun 8, 2015)

Pretty much every solution in the old thread had that problem solved... and most of them were pretty efficient too. Just look at some of that code. The one I posted also solves that problem.


----------



## Stefan (Jun 8, 2015)

molarmanful said:


> Okay, chill.



Sorry, was just really getting frustrating, and apparently yelling was actually necessary to finally get your attention and to get you acknowledge the issue.



molarmanful said:


> I decided to disregard it (for now) because I wasn't too sure of a way to solve the problem _efficiently_.



That's a really really bad reason. And you at least should've mentioned it instead of weakening the standard and making people who don't know better think it's ok. The publicity is the problem. Nobody would (or could) care if you had kept it to yourself.

I agree that code golf is allowed to simplify things. I'm not requesting that we must use random state scramblers for it, am I? But like Michael said and like you can see from the old thread that was pointed out to you already in the very first response in this thread, this issue is really not difficult.

That said, we could code-golf several categories:

25 random moves.
25 random moves, no side turned twice in a row.
25 random moves, also no trivial cancellations like R L R2 (i.e., what has been the standard for random-moves-scrambles for many years, for good reasons)
random state (i.e., what has been the standard for scrambles for several years now)
But only if those categories are made clear.


----------



## molarmanful (Jun 8, 2015)

Stefan said:


> That said, we could code-golf several categories:
> 
> 25 random moves.
> 25 random moves, no side turned twice in a row.
> ...



That'll work. I'm working on category 3 right now, but splitting into categories is a good idea.


----------



## qqwref (Jun 8, 2015)

Some versions of the script I posted at the start:

category 1:

```
<script>r=Math.random;for(j=25;j--;document.write("URFBLD"[m]+" 2'"[0|r()*3]+" "))m=0|r()*6</script>
```

category 2:

```
<script>r=Math.random;for(b=j=25;j;b-m?document.write("URFBLD"[j--,b=m]+" 2'"[0|r()*3]+" "):0)m=0|r()*6</script>
```


----------



## bobthegiraffemonkey (Jun 9, 2015)

A very quick attempt, first ever attempt at code golf I think. I use R, and tried category 1:

```
for(i in 1:25)cat(sample(c("U","D","R","L","F","B"),1),sample(c(" ","' ","2 "),1),sep="")
```


----------



## Stefan (Jun 9, 2015)

molarmanful said:


> bobthegiraffemonkey said:
> 
> 
> > I use R
> ...


No **** Sherlock.


----------



## molarmanful (Jun 9, 2015)

Stefan said:


> No **** Sherlock.



Wow, I must be REALLY tired.


----------



## qqwref (Jun 9, 2015)

Here are some 2x2x2 random-state scramblers. They may be broken due to typing/thinking errors but the concepts probably work.

First approach: permute each piece one by one, then orient each non-DFR piece one by one. DLB stays put. The function called e essentially returns a random element of the array, or an empty string, so we don't have to put empty strings in all of our permute/orient arrays. (353 bytes)

```
y=["R","R2","R'","RU","RU2"]
z=[v="L2F2D'L'DF'LD'LD",v+v]
document.write([["F","F2","F'","U'F'","UF2","RF"],x=["R'","R2","R","U'R'","U2R'"],["R'U'R","R'UR","B'U'B","R'U2R"],["U","U2","U'"],[w="R'ULU'RUL'U'",w+w],["U"+w+"U2"]].map(e=(j)=>{return j[0|Math.random()*(1+j.length)]||""}).join("")+[0,1,2,3,4].map((i)=>{return x[i]+e(z)+y[i]}).join("")+e(z))
```

Second approach: apply a 7-cycle from 0 to 6 times, a twisted 6-cycle (all pieces but DFL) from 0 to 5 times, a twisted 5-cycle (all pieces but DFL and DRB, twists DFL) from 0 to 4 times, etc. (181 bytes)

```
for(j=7;j--;)document.write(["UF'UF'RFU2R2F'R'","RU'R'UF2UF2U'F","R'F2RU'FU'F'U2","R'F'R2U2FUF'UR'","U2F2UF2UR'F'RF","F2R2U2RUF","F2R'F'RF2R'UFU2"][j].repeat(3*(j+1)*Math.random()))
```


----------



## Stefan (Jun 10, 2015)

I guess we need to split category 4 into "reasonable scramble length" and "not reasonable scramble length" 

And I can't run your first one. Tried it in Chrome and IE and both complain about a syntax error apparently somewhere in the "e=(j)=>{" and I don't know what to do.


----------



## molarmanful (Jun 10, 2015)

Stefan said:


> I guess we need to split category 4 into "reasonable length" and "not reasonable length"
> 
> And I can't run your first one. Tried it in Chrome and IE and both complain about a syntax error somewhere in the "e=(j)=>{" and I don't know what to do.



That's because the code is in ES6 (the new Javascript that's coming out - Note that current browser Javascript is ES5). The error is thrown at the => part, which is an ES6 arrow function syntax. The second script is also written in ES6 because of the String.prototype.repeat function (which is also a part of ES6).

I compiled the code and ran it, and yes - the scrambles do seem a bit long. And there's also the issue of move cancellation...

First code's sample:

```
UF2R2B'U'BR'ULU'RUL'U'R'ULU'RUL'U'UR'ULU'RUL'U'U2R'L2F2D'L'DF'LD'LDL2F2D'L'DF'LD'LDRR2L2F2D'L'DF'LD'LDL2F2D'L'DF'LD'LDR2RR'U'R'L2F2D'L'DF'LD'LDRUU2R'RU2
```

Second code's sample:

```
F2R'F'RF2R'UFU2F2R'F'RF2R'UFU2F2R2U2RUFU2F2UF2UR'F'RFU2F2UF2UR'F'RFU2F2UF2UR'F'RFU2F2UF2UR'F'RFU2F2UF2UR'F'RFU2F2UF2UR'F'RFU2F2UF2UR'F'RFR'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F'R2U2FUF'UR'R'F2RU'FU'F'U2R'F2RU'FU'F'U2R'F2RU'FU'F'U2RU'R'UF2UF2U'FRU'R'UF2UF2U'FRU'R'UF2UF2U'FRU'R'UF2UF2U'FUF'UF'RFU2R2F'R'
```


----------



## qqwref (Jun 10, 2015)

Psh, who needs move cancellation?  And yeah, the ()=>{} syntax is pretty new. It works for me in Firefox. As molarmanful mentions, .repeat() is the same.

Here's a 3x3x3 random state scrambler in 613 bytes. At least, it should be random state . It's like the 2x2x2 scrambler but it generates a random corner state (8 algs instead of 7) and then a random edge state (may swap UFR and UFB but it doesn't matter). I'm sure the algs can be improved, especially if you use slice turns.

```
for(j=8;j--;)document.write(["UF'R'U2F2LBR'UF'","F'UL'U'L'F'LF2","U'RFU'BR'U2LD'","RU'LDF2L2D'R'F","F2UR'F'L'D'RF'U","U2F'R2UF'DL","RU2F'UL'DBR2B2","FU'RFR'F2R'F'D'F"][j].repeat(3*(j+1)*(r=Math.random)()));for(j=12;j--;)document.write(["F2L2F2UL'RBU2L2U2B'LR'U'","R2FRBF2UL2U'F'LB'F2URU","L'D'B'LU'BDFL'F2L2F","B'RF'D2FRB2F2L2BDB2R2F2","B2LR2D'R'D2L'D'R'BU'B2L'B'","L2B'L2BL2B2L'B'U'F'L'D'L2DLF","B'L2BFU2B2R'D2F'D2R'D2BR2UL2","U2B2U2F2DL'FU'B'ULBF2R'F'R","D2L2B2D2R2U'B2F2LB'L2R2FLB2R2DB2","L2D2BL2B'LDB'L2U'F2L'FU'F'UL'F'","F2R2D'U2L2R2B'F2R2UL2FLF'LFUF'","DB2D2U'F2LBD2LR'DB2U2RUL2U'B"][j].repeat(2*(j+1)*r()))
```

Stefan, you had a really short solver a while back, right? Think you could turn it into a random-state scrambler?


----------



## Stefan (Jun 10, 2015)

molarmanful said:


> I compiled the code and ran it



Thanks, posting their outputs is very helpful. I note the number of moves: 96 for the first, 229 for the second. That's about 11 and 26 times the average number of moves that 2x2x2 positions need (~8.76 moves).



molarmanful said:


> there's also the issue of move cancellation



For random state scrambling that's ok. It makes them longer, but doesn't affect the distribution quality. In case it's not clear to everybody: Random *moves* scramblers are biased towards "easy states", so we want at least non--trivially-canceling 25 moves to achieve a somewhat decent distribution. Random *state* scramblers, by definition, have perfect distribution regardless of how their move sequences look. So cancellations are irrelevant, only the lengths should be considered a secondary criterion.



qqwref said:


> Stefan, you had a really short solver a while back, right? Think you could turn it into a random-state scrambler?



Maybe. It's been so long that I don't remember how it works and I might even need to relearn some Perl syntax to understand it . But here it is, in case you or someone else want to have a look.

How many moves does yours produce on average?


----------



## molarmanful (Jun 10, 2015)

qqwref said:


> And yeah, the ()=>{} syntax is pretty new. It works for me in Firefox.


Yep, Firefox currently is the only browser with ES6 support. I use Safari and Chrome, so I have to compile the code with Traceur.



Stefan said:


> For random state scrambling that's ok. It makes them longer, but doesn't affect the distribution quality. In case it's not clear to everybody: Random *moves* scramblers are biased towards "easy states", so we want at least non--trivially-canceling 25 moves to achieve a somewhat decent distribution. Random *state* scramblers, by definition, have perfect distribution regardless of how their move sequences look. So cancellations are irrelevant, only the lengths should be considered a secondary criterion.



I actually did not know that. Thanks!


----------



## qqwref (Jun 11, 2015)

411 byte random-state scrambler for the 3x3x3. Probably can be golfed down a bit but at least this is kind of readable.

```
r=Math.random
f=(b,a)=>{document.write((v=[[,"L2UL2","","L2U'L2","UFU'","U'B'U","R'","R","F'RF","R2","BR'B'","D2R2D2"],[,"R'","","F","F2","R","R2","D'R2D"]][b][a])+[["L2UL2U'L2B2U'B2DL2D'","ULU'L'B'UBLF'LFL2"],["F2UF2UF2U'R'U'RF2R'UR","R'F2L2D'L'DL'F2RU'","LF2R'DR'D'R2F2L'U'"]][b][0|r()*(2+b)]+v+v+v)}
g=(b,a)=>{j=0|r()*(a+1);f(b,a);j==a?f(b,a):j?(f(b,j),f(b,a)):1}
for(i=7;i---1;)g(1,i)
for(i=11;i---1;)g(0,i)
```



Spoiler



It's a Fisher–Yates shuffle done with Classic Pochmann. The f function swaps some piece with the buffer (UL or ULB) using a random one of (2 T perms or 3 Y perms) to give it a random orientation. The setup moves are all of order 2 or 4, so I can just do them 3 times to undo them. The g functions and the for loops do the actual shuffle; for a swap, there are 3 possible cases. If we swap two non-buffer pieces x and y, do f(x)f(y)f(x). If we swap a non-buffer piece x with the buffer, do f(x). And if we swap the piece x with itself, since we still need to orient, we want to do f(x)f(x). The buffer is always piece 0 so we can end the loop early and never need to worry about swapping it with itself (which is good, because the buffer's orientation is already set based on the other pieces).



EDIT: ~680 move average out of 10 trials. The one I posted before that was based on doing cycles over and over had a ~1530 move average out of 10 trials.


----------



## Stefan (Jun 11, 2015)

Quite clever, using setups with orders 2 and 4.

You could save a few bytes like this:

```
"L2UL2  L2U'L2 UFU' U'B'U R' R F'RF R2 BR'B' D2R2D2".split(" ")
```
(I just don't know why you have that preceding comma and what to do about that)

And you could use the "T perms" UFU'DFUD'FU'F2 and UFU'FUL'FLU'F2 (these swap DL with UR/RU) and use these setups:

```
" U U2 U' R R2 R' F'RF FU'F' BR'B' B'UB".split(" ")
```
And the same for corners.

At least for 2x2, I *think* you could use the "Y perm" RF2U'F'R'F2DLF either 1, 3 or 5 times. That swaps ULB with some orientation of DFR, so you don't need three Y perms. I'm not sure that this doesn't create biases, though, and whether it could be used for 3x3 as well. Might depend on the actual implementation and at least right now, I'm not going to write one.


----------



## molarmanful (Jun 11, 2015)

Stefan said:


> You could save a few bytes like this:
> 
> ```
> "L2UL2  L2U'L2 UFU' U'B'U R' R F'RF R2 BR'B' D2R2D2".split(" ")
> ...



You could also split using 0, for example:

```
"L2UL20L2U'L20UFU'0U'B'U0R'0R0F'RF0R20BR'B'0D2R2D2".split(0)
```


----------



## qqwref (Jun 12, 2015)

Stefan said:


> Quite clever, using setups with orders 2 and 4.


Thanks 



Stefan said:


> You could save a few bytes like this:
> 
> ```
> "L2UL2  L2U'L2 UFU' U'B'U R' R F'RF R2 BR'B' D2R2D2".split(" ")
> ...


The preceding comma actually says to leave an undefined value in the 0th element of the array (that value doesn't matter and it's shorter than ""). I like this idea though, or at least molarmanful's version.



Stefan said:


> And you could use the "T perms" UFU'DFUD'FU'F2 and UFU'FUL'FLU'F2 (these swap DL with UR/RU) and use these setups:
> 
> ```
> " U U2 U' R R2 R' F'RF FU'F' BR'B' B'UB".split(" ")
> ...


Huh? It's an interesting idea, but I think it'd mess up the corners in a way that's based on the edge permutation. Maybe that's OK since corners are already in a uniformly random position... but maybe if we do this in both ways, corners modifying edges and edges modifying corners, there will be some positions we can't get because (corner scramble + edge side effect, edge scramble + corner side effect) doesn't match that position for any possible two scrambles. I'll have to think about it.



Stefan said:


> At least for 2x2, I *think* you could use the "Y perm" RF2U'F'R'F2DLF either 1, 3 or 5 times. That swaps ULB with some orientation of DFR, so you don't need three Y perms. I'm not sure that this doesn't create biases, though, and whether it could be used for 3x3 as well. Might depend on the actual implementation and at least right now, I'm not going to write one.


I like the idea of using the same alg for all the cases, but I'm also not sure this will work. Since you need a twisted cycle (like the algs you posted) you have to twist some other piece, but the one that gets twisted will depend on the setup moves, so you might break the uniformly-random aspect. We could also write the Y perms as a random ["", "FR", "R'F'"] setup to a single Y perm alg, but I'm not sure if that's more efficient, since we'd have to do it for T perms as well.



molarmanful said:


> You could also split using 0, for example:
> 
> ```
> "L2UL20L2U'L20UFU'0U'B'U0R'0R0F'RF0R20BR'B'0D2R2D2".split(0)
> ```


Cool idea.


Down to 382:

```
r=Math.random
f=(b,a)=>{document.write((v=["0L2UL200L2U'L20UFU'0U'B'U0R'0R0F'RF0R20BR'B'0D2R2D2","0R'00F0F20R0R20D'R2D"][b].split(0)[a])+["L2UL2U'L2B2U'B2DL2D'0ULU'L'B'UBLF'LFL2","F2UF2UF2U'R'U'RF2R'UR0R'F2L2D'L'DL'F2RU'0LF2R'DR'D'R2F2L'U'"][b].split(0)[0|r()*(2+b)]+v+v+v)}
g=(b,a)=>{j=0|r()*(a+1);f(b,a);j-a?j?(f(b,j),f(b,a)):1:f(b,a)}
for(i=7;i---1;)g(1,i)
for(i=11;i---1;)g(0,i)
```


----------



## Stefan (Jun 12, 2015)

qqwref said:


> Thanks but maybe if we do this in both ways, corners modifying edges and edges modifying corners, there will be some positions we can't get because (corner scramble + edge side effect, edge scramble + corner side effect) doesn't match that position for any possible two scrambles. I'll have to think about it.


Oops, yes, doing it both ways might not work. Imagine a different puzzle where the "corners" are just the places/numbers 1 to 8 and the edges are just the places/numbers -1 to -8. And the "swap algorithm" swaps corners at places 1 and s and also swaps edges at places -1 and -s. Then the corner perm and edge perm will always be the same. Not sure how comparable that is, but it does show that one has to be careful.

But you can certainly use it for edges and then your current way for corners, right? And maybe for corners it might be beneficial to swap ULB with DFR orientations instead of URF orientations. Then all setups are just a single move. Not sure about the swap alg lengths, though.



qqwref said:


> I like the idea of using the same alg for all the cases, but I'm also not sure this will work. Since you need a twisted cycle (like the algs you posted) you have to twist some other piece, but the one that gets twisted will depend on the setup moves, so you might break the uniformly-random aspect.


Ah, now I remember why I did it for 2x2 and was unsure about making it work for 3x3 . I was thinking of keeping the DLB corner fixed permutation-wise, and use it for the orientation side-effect. If you use setup moves ""/F/F2/F'/R/R2, then it's always that DLB corner that gets twisted.


----------

