• Welcome to the Speedsolving.com, home of the web's largest puzzle community!
    You are currently viewing our forum as a guest which gives you limited access to join discussions and access our other features.

    Registration is fast, simple and absolutely free so please, join our community of 35,000+ people from around the world today!

    If you are already a member, simply login to hide this message and begin participating in the community!

Simple PHP scrambler

Johannes91

Member
Joined
Mar 28, 2006
Messages
1,341
I don't know much Ruby, but one thing stands out: I think it would make sense to pass scramble_length as a parameter. And at least in Python it's more efficient (and IMO more elegant) to use an array and join it once instead of repeatedly concatenating strings:
Code:
scramble = []
...
scramble.push(turns[axis].rand + variants.rand)
...
scramble.join(" ")

FWIW, here's a Haskell scrambler I wrote a while ago:
Code:
getScramble :: Int -> IO FlatAlg
getScramble = liftM fromJust . getGeneralScramble (map (flip (,) [1,2,3]) [U,D,F,B,R,L])

getGeneralScramble :: [(Face,[Int])] -> Int -> IO (Maybe FlatAlg)
getGeneralScramble xs n = do maybeFaces <- getRandomFaces (map fst $ filter (not . null . snd) xs) n
                             case maybeFaces of
                                Nothing    -> return Nothing
                                Just faces -> do suffixes <- mapM (liftM (Suffix . fromJust) . pick . fromJust . flip lookup xs) faces
                                                 return $ Just $ FlatAlg $ zipWith FaceMove faces suffixes

getRandomFaces :: [Face] -> Int -> IO (Maybe [Face])
getRandomFaces fcs = flip rec []
                   where rec :: Int -> [Face] -> IO (Maybe [Face])
                         rec 0 acc = return $ Just acc
                         rec n acc = do maybeFace <- pick (filter p fcs)
                                        case maybeFace of
                                           Nothing -> return Nothing
                                           Just x  -> rec (n-1) (x:acc)
                                   where p = case acc of
                                                []     -> const True
                                                (x:[]) -> (/= x)
                                                (x:y:_) | isSameSliceFace x y -> not . isSameSliceFace x
                                                        | otherwise           -> (/= x)

pick :: [a] -> IO (Maybe a)
pick [] = return Nothing
pick xs = liftM (Just . (xs !!)) $ randomRIO (0, length xs - 1)
 

joey

Member
Joined
Apr 8, 2007
Messages
4,410
WCA
2007GOUL01
YouTube
cardologist
Code:
def cube_scramble1(turns,scramble_length = 25)
    variants = ['', "'", '2']
    axis = rand turns.size
    (0..scramble_length).map do
      axis = (axis + rand(turns.size - 1) + 1) % turns.size
      turns[axis].rand + variants.rand
    end.join(" ")
end
I havn't tested that (too lazy), but I'm pretty sure it should work.
 

tim

Member
Joined
Nov 22, 2006
Messages
1,692
Location
Karlsruhe, Germany
WCA
2007HABE01
YouTube
cin9247
I don't know much Ruby, but one thing stands out: I think it would make sense to pass scramble_length as a parameter. And at least in Python it's more efficient (and IMO more elegant) to use an array and join it once instead of repeatedly concatenating strings:
Code:
scramble = []
...
scramble.push(turns[axis].rand + variants.rand)
...
scramble.join(" ")
Thanks, Johannes. In Ruby you can join an array in the same way, too. I don't know, why i didn't think about that. I'll change that immediately.
And for the scramble_length: Actually the method is part of the puzzle model, so the scramble_length is alway given (from the database), if you call the method. (I should've removed it for this post)

/edit: and thanks to joey, your method works and i use it from now on :). (argh, how could i forget "map"?)
 
Last edited:

mrCage

Member
Joined
Jun 17, 2006
Messages
654
Hi :)

It's nice to see other scramblers written in other languages. However for the new FMC site my only options are really like this: PHP, Perl, Javascript, COM object. Javascript is not a real option as it has to be done serverside, and i do not have time to get into ajax or similar technologies. As the site is hosted on a linux server the COM alternative is also not possible - i have no way to set up a virtual OS or anything like that. Perl is a good alternative, but for portabliity i just use plain PHP, not using PEAR or PECL or anything like that. ONE scramble is generated pr week (rollover) so speed is not really an issue The most important thing is to make valid (non-simplifiable) scrambles. Also, code that is very clear is better than tricky very compact scramblers. Easier to maintain, expand, port the code for future use. I believe that how i coded it can be ported easily to virtually any language (procedural ones at least).

- Per
 

Johannes91

Member
Joined
Mar 28, 2006
Messages
1,341
Here's a simpler (but much less general) Haskell scrambler:
Code:
module SimpleScrambler where

import System.Random (randomRIO)
import Data.List ((\\))

getScramble :: Int -> IO String
getScramble n = fmap unwords $ mapM showFace =<< getFaces n
    where showFace x = fmap ("UFRLBD" !! x :) $ pick ["", "'", "2"]

getFaces :: Int -> IO [Int]
getFaces = go [] where
    go acc 0 = return acc
    go acc n = pick zs >>= \z -> go (z : acc) (n - 1)
        where zs = case acc of
                      (x:y:_) | x + y == 5 -> [0..5] \\ [x,y]
                      (x:_)                -> [0..5] \\ [x]
                      (_)                  -> [0..5] \\ []

pick :: [a] -> IO a
pick xs = fmap (xs !!) $ randomRIO (0, length xs - 1)
And a 127-byte Perl scrambler (could certainly be shortened, but I have other things to think about now):
Code:
perl -le 'for(0..24){$a=int rand 6 until$a-$a[0]&&$a+$a[0]-5|$a-$a[1];@a=($a,@a)}print join" ",map{(U,F,R,L,B,D)[$_].(v39,2)[rand 3]}@a'
Javascript is not a real option as it has to be done serverside, and i do not have time to get into ajax or similar technologies.
<nitpick>
Ajax basically lets client-side JavaScript make requests to server-side programs. It doesn't have much to do with server-side JavaScript.
</nitpick>

I believe that how i coded it can be ported easily to virtually any language (procedural ones at least).
That's a very important distinction to make. Not all languages have such things as loops and variables.
 
Last edited:

mrCage

Member
Joined
Jun 17, 2006
Messages
654
Here's a simpler (but much less general) Haskell scrambler:
Code:
module SimpleScrambler where
 
import Data.List
import Control.Monad
import System.Random
 
getScramble :: Int -> IO String
getScramble n = liftM concat $ mapM showFace =<< getFaces n
              where showFace x = return . ("UFRLBD" !! x :) =<< pick [" ", "' ", "2 "]
 
getFaces :: Int -> IO [Int]
getFaces = rec []
         where rec acc 0 = return acc
               rec acc n = do z <- pick zs
                              rec (z:acc) (n-1)
                         where zs = case acc of
                                       (x:y:_) | x + y == 5 -> delete y $ delete x [0..5]
                                       (x:_)                -> delete x [0..5]
                                       []                   -> [0..5]
 
pick :: [a] -> IO a
pick xs = liftM (xs !!) $ randomRIO (0, length xs - 1)
And a 136-byte Perl scrambler (could certainly be shortened, but I have other things to think about now):
Code:
perl -le 'for(0..24){do{$a=int rand 6}until$a-$a[-1]and$a+$a[-1]-5||$a-$a[-2];[email protected],$a}print join" ",map{qw<U F R L B D>[$_].(v39,2)[rand 3]}@a'
Javascript is not a real option as it has to be done serverside, and i do not have time to get into ajax or similar technologies.
<nitpick>
Ajax basically lets client-side JavaScript make requests to server-side programs. It doesn't have much to do with server-side JavaScript.
</nitpick>

I believe that how i coded it can be ported easily to virtually any language (procedural ones at least).
That's a very important distinction to make. Not all languages have such things as loops and variables.
Tell me one PROCEDURAL common language that does not have loops and variables. I can think of some non-procedural ones. I never said server side javascript. I said i ignored javascript because i do not have time to get into ajax and similar.

It is best sometimes to just read between the lines.

And btw, i do not have ANY intention to switch to random position scrambling for FMC. The FMC site does not intend to follow WCA ragulations at all times. It will remain independent in the foreseeable future.

Any site is welcome to link to the fmc site (how could i prevent it anyway??). I could prevent linking to pictures, files etc on the site. But there is virtually non such useful content to "rip", and thus steal bandwidth :)

-PKF
 

Johannes91

Member
Joined
Mar 28, 2006
Messages
1,341
Why did you quote the whole long post when you were only replying to a couple of specific parts?

I believe that how i coded it can be ported easily to virtually any language (procedural ones at least).
That's a very important distinction to make. Not all languages have such things as loops and variables.
Tell me one PROCEDURAL common language that does not have loops and variables.
I just pointed out that saying virtually any language would've been extremely naïve. You added the word procedural, but just as a sidenote, assuming almost all languages are procedural. I can think of several language familys/paradigms in which it would be easier to write a scrambler from scratch than to adapt an imperative/procedural one.

I never said server side javascript. I said i ignored javascript because i do not have time to get into ajax and similar.
But you did say that the scrambler needs to be server-side. And I said that Ajax wouldn't help, so not having time to get into Ajax shouldn't be a reason to ignore JavaScript...

I could prevent linking to pictures, files etc on the site.
How? (This is a sincere question, I'm interested and don't know.)
 

mrCage

Member
Joined
Jun 17, 2006
Messages
654
I could prevent linking to pictures, files etc on the site.
How? (This is a sincere question, I'm interested and don't know.)
I meant hot linking to be more specific. It is a standard feature of most hosting control panels. How it works is quite trivial. Only local requests are allowed. I'm not sure if this is an Apache only feature, but i have only seen that on linux/apache hosting (i think). Sorry for late reply - my forum reading is a bit random :eek:

-Per
 

badmephisto

Member
Joined
Aug 29, 2007
Messages
837
YouTube
badmephisto
and finally a python version :) :
edit: I just wish so much I could get rid of the variable 'a' in the loop! I cant think of anything simple

Code:
from random import randrange
def scramble(length=25):
    turns=['U','D','F','B','R','L']
    vars = ["'", "2", ""]
    out=[]
    while len(out) != length:
        a=turns[randrange(0,len(turns)-1)]
        if len(out)==0 or out[len(out)-1] != a: out.append(a)
    return " ".join(map(lambda x: x+vars[randrange(0,len(vars)-1)], out))
edit: actually thats wrong, sigh! but easy fix
 
Last edited:

Johannes91

Member
Joined
Mar 28, 2006
Messages
1,341
Code:
$ python
>>> [paste badmephisto's code here]
>>> scramble(25)
"D2 B2 F2 R2 [b]B2 F' B' F2[/b] D2 U2 R2 D' U' B2 F2 D' F2 D2 U2 R' F' U2 B2 U2 B'"
Edit:
edit: I just wish so much I could get rid of the variable 'a' in the loop! I cant think of anything simple
Here's one way to get rid of it (it's still not a proper scrambler). Just add a random turn, if it's bad, remove it.
Code:
from random import randrange
def scramble(length=25):
    turns = "UDFBRL"
    vars = ["'", "2", ""]
    out = []
    while len(out) < length:
        out.append(turns[randrange(0, len(turns) - 1)])
        if len(out) > 1 and out[-1] == out[-2]: out.pop()
    return " ".join(map(lambda x: x + vars[randrange(0, len(vars) - 1)], out))
 
Last edited:

badmephisto

Member
Joined
Aug 29, 2007
Messages
837
YouTube
badmephisto
yes i know. but the whole point was that i wanted to have a single line in that while loop :)

Anyway I forgot about that little glitch, i think this will do it. But now it doesnt look that elegant :(
In addition I can forget trying to make that a single line while-loop without going over like 200 characters :)

Code:
from random import randrange
def scramble(length=25):
    turns=['U','F','R','D','B','L']
    vars = ["'", "2", ""]
    out=[]
    while len(out) != length:
        a=turns[randrange(0,len(turns)-1)]
        if len(out)==0 or (out[-1] != a and out[-1] != turns[(turns.index(a)+3)%len(turns)]): out.append(a)
    return " ".join(map(lambda x: x+vars[randrange(0,len(vars)-1)], out))
basically re-arranged turns list s.t. parallel faces are 3 spaces apart, and then add 3 and mod for the additional check.
 
Last edited:

Johannes91

Member
Joined
Mar 28, 2006
Messages
1,341
Anyway I forgot about that little glitch, i think this will do it.
Now it rejects R L R, but also R L, which should be fine. How I fixed it: If out is [..., a, b, c], reject c if b = c. Otherwise check if b and c are opposite each other, if they are, accept c iff it's not equal to a.

But now it doesnt look that elegant :(
One change that IMO makes it a bit more elegant is to put a to the out array instead of turns[a], and change them just before returning.

basically re-arranged turns list s.t. parallel faces are 3 spaces apart, and then add 3 and mod for the additional check.
Another way is to use [U,F,R,L,B,D] ordering and check if the sum equals 5.

Code:
from random import randrange
def scramble(length=25):
    turns = "UFRLBD"
    vars = ["'", "2", ""]
    out = []
    while len(out) < length:
        a = randrange(0, len(turns) - 1)
        if len(out) == 0 or a != out[-1] and (len(out) == 1 or a + out[-1] != 5 or a != out[-2]): out.append(a)
    return " ".join(map(lambda x: turns[x]+vars[randrange(0,len(vars)-1)], out))
That's quite a mess, but works. Would probably be better to split the conditional in several elifs.
 

badmephisto

Member
Joined
Aug 29, 2007
Messages
837
YouTube
badmephisto
you are right Johannes. I jumped into coding way too fast without thinking about all the subtleties involved. I like the solution with sum equaling to 5, its an interesting way to get that check done.
 

JBCM627

Member
Joined
Apr 27, 2008
Messages
799
Location
Ohio, USA
WCA
2006MERT01
HTML is not a programming language, so you can't write a scrambler with it. The one I posted is in javascript, which you can put in an html file if you wish.
 

TheCubers

Member
Joined
Jul 18, 2008
Messages
27
HTML is not a programming language, so you can't write a scrambler with it. The one I posted is in javascript, which you can put in an html file if you wish.
Just Read Over it again and realized :)

HTML:
<html>
<head>
<script type="text/javascript">
function makeScramble($length)
 {
  /*
  $faces = array('U','D,'F','B','R','L')
  $taken = array(0,0,0,0,0,0,0);
  $numturns = array(1,1,1,1,1,1,1,2,2);
  $axis = array(1,1,1,2,2,3,3);
  $modifiers = array('',','\'','2');
  */
  $faces[1] = 'U';
  $faces[2] = 'D';
  $faces[3] = 'F';
  $faces[4] = 'B';
  $faces[5] = 'R';
  $faces[6] = 'L';
  $taken[1] = 0;
  $taken[2] = 0;
  $taken[3] = 0;
  $taken[4] = 0;
  $taken[5] = 0;
  $taken[6] = 0;
  $numturns[1] = 1;
  $numturns[2] = 1;
  $numturns[3] = 1;
  $numturns[4] = 1;
  $numturns[5] = 1;
  $numturns[6] = 1;
  $numturns[7] = 2;
  $numturns[8] = 2;
  $modifiers[1] = '';
  $modifiers[2] = '2';
  $modifiers[3] = '\'';
  $axis[1] = 1;
  $axis[2] = 1;
  $axis[3] = 2;
  $axis[4] = 2;
  $axis[5] = 3;
  $axis[6] = 3;
 
  $prevaxis = -1;
  $scramble='';
  $totturns = 0;
  do {
  //select current axis to work on
   do {
    $curraxis = rand(1,3);
   } while ($curraxis == $prevaxis);
   $prevaxis = $curraxis; //update previous axis
   //select number of turns on this axis
   if ($totturns<($length-1)) {
    $num = $numturns[rand(1,8)];
   } else {
    $num = 1;
   } 
   for ($j=1; $j<=$num; $j++) {
    do {
     $faceindex=rand(1,6);
     $modifierindex=rand(1,3);
    } while (($axis[$faceindex] != $curraxis) || ($taken[$faceindex] == 1));
    $taken[$faceindex] = 1;
    $turn = $faces[$faceindex].$modifiers[$modifierindex]." ";
    $scramble = $scramble.$turn;
    $totturns++;
   }
   for ($j=1; $j<=6; $j++) {
    $taken[$j] = 0;
   }
  } while ($totturns<$length);
  return $scramble;
 }
 
$mylength = 30;
$myscramble = makeScramble($mylength);
...
(applet and/or database code ??)
...
...
</script>
</head>
<body>

<input type="button" onclick="makeScramble($length)" value="Display Scramble" />

</body>
</html>
is what i have, doesn't seem to work
 
Last edited:

mrCage

Member
Joined
Jun 17, 2006
Messages
654
Hi :)

You cannot convert php serverside code into javascript that easily. But the steps should work the same nevertheless :)

- Per
 

ezh

Member
Joined
Feb 5, 2008
Messages
12
Since we're all sharing our scramble generators, here's mine, written in JavaScript:

PHP:
function scramble(length) {
    var scramble=[], face=Math.floor(5*Math.random()), sameAxis;
    while(scramble.length < length) {
        var faceDiff = sameAxis ? (Math.random()>.5 ? 4 : 1) + Math.floor(2*Math.random()) : Math.floor(4*Math.random())+1;
        sameAxis = faceDiff == 3;
        face += faceDiff;
        scramble.push('URFDLB'.charAt(face%6) + (1>3*Math.random() ? '' : (Math.random()>.5 ? '2' : "'")));
    }
    return scramble.join(' ');
}
 
Top