In bici con Rubik's


43

Mentre girava pigramente intorno al mio cubo di Rubik , mio ​​figlio notò che continuava a tornare allo stato risolto. Sono abbastanza sicuro che all'inizio pensasse che fosse una sorta di magia voodoo, ma ho spiegato che se continui a ripetere la stessa sequenza di mosse, tornerà sempre al suo stato originale. Infine.

Naturalmente, da bambino, ha dovuto provarlo da solo e ha scelto una sequenza "casuale" che pensava sarebbe stata complicata. Ha perso la traccia dopo circa dieci ripetizioni e mi ha chiesto quante volte avrebbe dovuto ripeterlo. Non conoscendo la sequenza che stava usando, gli dissi che non lo sapevo, ma che potevamo scrivere un programma per scoprirlo.

È qui che entri. Certo, potrei solo montare qualcosa, ma vorrebbe scriverlo da solo. Non è ancora un dattilografo molto veloce, quindi ho bisogno del programma più breve possibile .

Obbiettivo

Data una sequenza di turni, emettere il minor numero di volte in cui deve essere eseguito per riportare il cubo al suo stato originale. Questo è il golf del codice, quindi vince meno byte. È possibile scrivere un programma o una funzione e si applicano tutte le altre impostazioni predefinite usuali.

Ingresso

L'input è una sequenza di mosse, presa come una stringa, un elenco o un altro formato adatto alla tua lingua. Sentiti libero di usare un separatore (o meno) tra le mosse se in forma di stringa.

Ci sono sei mosse "di base" che devono essere prese in considerazione, insieme alle loro inversioni:

R - Turn the right face clockwise
L - Turn the left face clockwise
U - Turn the up (top) face clockwise
D - Turn the down (bottom) face clockwise
F - Turn the front face clockwise
B - Turn the back face clockwise

Gli inversi sono rappresentati aggiungendo un segno primo 'dopo la lettera. Ciò indica che si gira quella faccia in senso antiorario, quindi F'si gira la faccia anteriore in senso antiorario e si riporta F F'immediatamente allo stato originale.

Per gli interessati, questa sfida sta usando un set limitato di Singmaster Notation . Ruwix ha delle belle animazioni se vuoi vederlo in azione.

Produzione

L'output è semplicemente il numero minimo di volte in cui deve essere eseguita la sequenza di input.

Esempi

Input                Output

FF'               ->      1
R                 ->      4
RUR'U'            ->      6
LLUUFFUURRUU      ->     12
LUFFRDRBF         ->     56
LF                ->    105
UFFR'DBBRL'       ->    120
FRBL              ->    315

Ecco un risolutore (abbastanza ingenuo) per confrontare le tue risposte, scritto in Java. Accetta anche 2per doppie mosse (quindi il quarto caso è equivalente a L2U2F2U2R2U2).

import java.util.ArrayList;
import java.util.List;

public class CycleCounter{

    public static void main(String[] args){
        int[] cube = new int[54];
        for(int i=0;i<54;i++)
            cube[i] = i;

        String test = args.length > 0 ? args[0] : "RUR'U'";
        List<Rotation> steps = parse(test);
        System.out.println(steps.toString());

        int count = 0;
        do{
            for(Rotation step : steps)
                cube = step.getRotated(cube);
            count++;
        }while(!isSorted(cube));

        System.out.println("Cycle length for " + test + " is " + count);        
    }

    static List<Rotation> parse(String in){
        List<Rotation> steps = new ArrayList<Rotation>();
        for(char c : in.toUpperCase().toCharArray())
            switch(c){
                case 'R':steps.add(Rotation.R);break;
                case 'L':steps.add(Rotation.L);break;
                case 'U':steps.add(Rotation.U);break;
                case 'D':steps.add(Rotation.D);break;
                case 'F':steps.add(Rotation.F);break;
                case 'B':steps.add(Rotation.B);break;
                case '\'':
                    steps.add(steps.get(steps.size()-1));
                case '2':
                    steps.add(steps.get(steps.size()-1));
                    break;
            }
        return steps;
    }

    static boolean isSorted(int[] in){for(int i=0;i<in.length-1;i++)if(in[i]>in[i+1])return false;return true;}

    enum Rotation{
        R(new int[]{-1,-1,42,-1,-1,39,-1,-1,36, -1,-1,2,-1,-1,5,-1,-1,8, 20,23,26,19,-1,25,18,21,24, -1,-1,11,-1,-1,14,-1,-1,17, 35,-1,-1,32,-1,-1,29,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1}),
        L(new int[]{9,-1,-1,12,-1,-1,15,-1,-1, 27,-1,-1,30,-1,-1,33,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 44,-1,-1,41,-1,-1,38,-1,-1, -1,-1,6,-1,-1,3,-1,-1,0, 47,50,53,46,-1,52,45,48,51}),
        U(new int[]{2,5,8,1,-1,7,0,3,6, 45,46,47,-1,-1,-1,-1,-1,-1, 9,10,11,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, 18,19,20,-1,-1,-1,-1,-1,-1, 36,37,38,-1,-1,-1,-1,-1,-1}),
        D(new int[]{-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,24,25,26, -1,-1,-1,-1,-1,-1,42,43,44, 29,32,35,28,-1,34,27,30,33, -1,-1,-1,-1,-1,-1,51,52,53, -1,-1,-1,-1,-1,-1,15,16,17}),
        F(new int[]{-1,-1,-1,-1,-1,-1,18,21,24, 11,14,17,10,-1,16,9,12,15, 29,-1,-1,28,-1,-1,27,-1,-1, 47,50,53,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,8,-1,-1,7,-1,-1,6}),
        B(new int[]{51,48,45,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,0,-1,-1,1,-1,-1,2, -1,-1,-1,-1,-1,-1,26,23,20, 38,41,44,37,-1,43,36,39,42, 33,-1,-1,34,-1,-1,35,-1,-1});

        private final int[] moves;
        Rotation(int[] moves){
            this.moves = moves;
        }

        public int[] getRotated(int[] cube){
            int[] newCube = new int[54];
            for(int i=0;i<54;i++)
                if(moves[i]<0)
                    newCube[i] = cube[i];
                else
                    newCube[moves[i]] = cube[i];
            return newCube;
        }
    }
}

"in senso orario" significa "in senso orario quando ci si trova di fronte" suppongo?
msh210,

@ msh210 Corretto.
Geobits,

7
Per quanto riguarda la pedanteria, penso che dovresti rendere esplicito che vuoi il numero più piccolo che è sufficiente. Altrimenti potrei semplicemente generare le dimensioni del gruppo e citare il teorema di Lagrange ...
Peter Taylor,

2
@PeterTaylor Pedantry accettato.
Geobits,

4
Io possa offrire una taglia di 500 punti per una soluzione in Shuffle. Non sono ancora sicuro.
lirtosiast,

Risposte:


16

Pyth, 66 63 byte

l.uum.rW}Hdd@_sm_B.iFP.>c3Zk3xZHG_r_Xz\'\39Nf!s}RTcZ2y=Z"UDLRFB

Provalo online: Dimostrazione o Test Suite . Si noti che il programma è piuttosto lento e il compilatore online non è in grado di calcolare la risposta RU2D'BD'. Ma assicurati che può calcolarlo sul mio laptop in circa 12 secondi.

Il programma (per sbaglio) accetta anche 2doppie mosse.

Spiegazione completa:

Scramble Parse:

Per prima cosa mi occuperò dei segni primi 'nelle stringhe di input. Semplicemente li sostituisco con 3e decodifico questa stringa. Dato che il formato di decodifica di Pyth richiede il numero davanti al carattere, invertisco prima la stringa. _r_Xz\'\39. Quindi dopo lo riavvolgo.

Descrivi lo stato del cubo risolto:

=Z"UDLRFBassegna la stringa con tutte e 6 le mosse a Z.

Possiamo descrivere uno stato del cubo descrivendo la posizione per ogni pezzo del cubo. Ad esempio possiamo dire che il bordo, che dovrebbe essere in UL (Su-Sinistra) è attualmente in FR (Fronte-Destra). Per questo ho bisogno di generare tutti i pezzi del cubo risolto: f!s}RTcZ2yZ. yZgenera tutti i possibili sottoinsiemi di "UDLRFB". Questo ovviamente genera anche il sottoinsieme "UDLRFB"e il sottoinsieme "UD". Il primo non ha alcun senso, poiché non c'è nessun pezzo visibile da tutti e 6 i lati, e il secondo non ha alcun senso, poiché non c'è un bordo, che è visibile dall'alto e dal basso . Pertanto rimuovo tutti i sottoinsiemi, che contengono la sequenza secondaria "UD", "LR"o "FB". Questo mi dà i seguenti 27 pezzi:

'', 'U', 'D', 'L', 'R', 'F', 'B', 'UL', 'UR', 'UF', 'UB', 'DL', 'DR', 'DF', 'DB', 
'LF', 'LB', 'RF', 'RB', 'ULF', 'ULB', 'URF', 'URB', 'DLF', 'DLB', 'DRF', 'DRB'

Ciò include anche la stringa vuota e tutte le sei stringhe di 1 lettera. Potremmo interpretarli come il pezzo nel mezzo del cubo e i 6 pezzi centrali. Ovviamente non sono richiesti (poiché non si muovono), ma li terrò.

Fare alcune mosse:

Farò alcune traduzioni di stringhe per eseguire una mossa. Per visualizzare l'idea, guarda l'angolo in URF. Cosa succede quando faccio una Rmossa? L'adesivo sul Uviso si sposta sul Bviso, l'adesivo si Fsposta sul Uviso e l'adesivo sul Rviso rimane sul Rviso. Possiamo dire che il pezzo si URFsposta nella posizione BRU. Questo modello è vero per tutti i pezzi sul lato destro. Ogni adesivo che si trova sul Fviso si sposta sul Uviso quando Rviene eseguita una mossa, ogni adesivo che si trova sul Uviso si sposta sul Bviso, ogni adesivo sulle Bmosse De ogni adesivo sulla si Dsposta suF. Possiamo decodificare le modifiche di una Rmossa come FUBD.

Il seguente codice genera tutti i 6 codici necessari:

_sm_B.iFP.>c3Zk3
['BRFL', 'LFRB', 'DBUF', 'FUBD', 'RDLU', 'ULDR']
    ^       ^       ^       ^       ^       ^
 U move  D move  L move  R move  F move  B move

E eseguiamo un passaggio Hallo stato del cubo Gcome segue:

m.rW}Hdd@...xZHG
m              G   map each piece d in G to:
 .rW   d              perform a rotated translation to d, but only if:
    }Hd                  H appears in d (d is currently on the face H)
            xZH           get the index of H in Z
        @...              and choose the code in the list of 6 (see above)

Conta il numero di ripetizioni:

Il resto è praticamente banale. Eseguo semplicemente l'input scramble ripetutamente sul cubo risolto fino a raggiungere una posizione che ho visitato in precedenza.

l.uu<apply move H to G><parsed scramble>N<solved state>
u...N   performs all moves of the scramble to the state N
.u...   do this until cycle detected, this returns all intermediate states
l       print the length

13

GAP, 792 783 782 749 650 byte

Questo sembra funzionare. Se si incasina qualcosa, fammi sapere.

Grazie a @Lynn per avermi suggerito di scomporre alcune delle mosse primitive.

Grazie a @Neil per avermi suggerito che invece di Inverse(X)usare X^3.

Esempio di utilizzo: f("R");

R:=(3,39,21,48)(6,42,24,51)(9,45,27,54)(10,12,18,16)(13,11,15,17);L:=(1,46,19,37)(4,49,22,40)(7,52,25,43)(30,36,34,28)(29,33,35,31);U:=(1,10,27,28)(2,11,26,29)(3,12,25,30)(37,43,45,39)(40,44,42,38);A:=R*L^3*F*F*B*B*R*L^3;D:=A*U*A;;F:=(1,3,9,7)(2,6,8,4)(10,48,36,43)(13,47,33,44)(16,46,30,45);B:=(27,25,19,21)(26,22,20,24)(39,28,52,18)(38,31,53,15)(37,34,54,12);d:=NewDictionary((),true);AddDictionary(d,'R',R);AddDictionary(d,'L',L);AddDictionary(d,'U',U);AddDictionary(d,'D',D);AddDictionary(d,'F',F);AddDictionary(d,'B',B);f:=function(s) local i,p,b,t;p:=();
for c in s do if c='\'' then t:=t^2;else t:=LookupDictionary(d,c);fi;p:=p*t;od;return Order(p);end;

Ecco il codice non golfato con un po 'di spiegazione

  # Here we define the primitive moves
R:=(3,39,21,48)(6,42,24,51)(9,45,27,54)(10,12,18,16)(13,11,15,17);
L:=(1,46,19,37)(4,49,22,40)(7,52,25,43)(30,36,34,28)(29,33,35,31);
U:=(1,10,27,28)(2,11,26,29)(3,12,25,30)(37,43,45,39)(40,44,42,38);
#D:=(7,34,21,16)(8,35,20,17)(9,36,19,18)(48,46,52,54)(47,49,53,51);
F:=(1,3,9,7)(2,6,8,4)(10,48,36,43)(13,47,33,44)(16,46,30,45);
B:=(27,25,19,21)(26,22,20,24)(39,28,52,18)(38,31,53,15)(37,34,54,12);

# Here we define D in terms of other primitive moves, saving on bytes
# Thanks @Lynn
# This is actually doable with a maximum of 3 of the primitive moves
# if a short enough sequence can be found.
D:=U^(R*L^3*F*F*B*B*R*L^3);

# create dictionary and add moves to it with appropriate char labels
d:=NewDictionary((),true);
AddDictionary(d,'R',R);
AddDictionary(d,'L',L);
AddDictionary(d,'U',U);
AddDictionary(d,'D',D);
AddDictionary(d,'F',F);
AddDictionary(d,'B',B);

f:=function(s)
    local c,p,t;

    # p will become the actual permutation passed to the function
    p:=();

    for c in s do
        if c='\'' then
            # The last generator we mutiplied (that we still have in t)
            # should have been its inverse. Compensate by preparing to
            # multiply it two more times to get t^3=t^-1. Thanks @Neil.
            t:=t^2;
        else
            t:=LookupDictionary(d,c);
        fi;
        p:=p*t;
    od;

    return Order(p);

end;

Ogni mossa è una quarta radice dell'identità, quindi il tuo Inverse non è necessario.
Neil,

Probabilmente puoi sostituirlo 45con 5nelle tue permutazioni e salvare tre byte.
Lynn,

Un risultato di Benson che ho trovato in Singmaster, 1981 dice: "Sia A = RL⁻¹F²B²RL⁻¹, quindi AUA = D." In effetti, A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;è più breve della tua definizione di D(ma non posso provarlo ...)
Lynn

GAP non ti consente davvero di scrivere ^-1per inversioni, a proposito?
Lynn,

Sì, ho completamente spaziato sull'uso di ^ -1. Il che presumo sia praticamente la stessa cosa che diceva @Neil, tranne invece con ^ 3 (che in realtà è la più breve). Inoltre, sì, potrei scomporre le mosse in altre mosse e dovrei essere in grado di salvare diversi byte facendo ciò, sarebbe solo una questione di trovare la decomposizione più breve.
Liam,

10

Mathematica, 413 401 byte

Evaluate[f/@Characters@"RFLBUD"]=LetterNumber@"ABFEJNRMDAEHIMQPCDHGLPTOBCGFKOSNADCBILKJEFGHQRST"~ArrayReshape~{6,2,4};
r[c_,l_]:=(b=Permute[c,Cycles@f@l];MapThread[(b[[#,2]]=Mod[b[[#,2]]+{"F","B","L","R"}~Count~l{-1,1,-1,1},#2])&,{f@l,{3,2}}];b);
p@s_:=Length[c={#,0}&~Array~20;NestWhileList[Fold[r,#,Join@@StringCases[s,x_~~t:""|"'":>Table[x,3-2Boole[t==""]]]]&,c,(Length@{##}<2||c!=Last@{##})&,All]]-1

spiegazioni

Cubo di Rubik è costituito con 20 mobili cubetti (8 angoli, 12 bordi). A ogni cucciolo può essere assegnato un numero:

angoli :

N   starting position
1     UFR
2     UBR
3     UBL
4     UFL
5     DFR
6     DBR
7     DBL
8     DFL

bordi :

N   starting position
9     UF
10    UR
11    UB
12    UL
13    FR
14    BR
15    BL
16    FL
17    DF
18    DR
19    DB
20    DL

Si noti che quando il cubo viene attorcigliato, i cubi non si trovano più nella posizione iniziale. Ad esempio, al Rtermine, il cubie 1passa da UFRuna nuova posizione UBR.

In tale notazione, una virata di 90 gradi può essere descritta da 8 movimenti di cubetti. Ad esempio, Rè descritto da

from  to
UFR   UBR
UBR   DBR
DBR   DFR
DFR   UFR
UR    BR
BR    DR
DR    FR
FR    UR

Poiché ogni cubo ha una posizione iniziale unica, ogni posizione ha un cubo iniziale unico. Vale a dire, la regola UFR->UBRè giusta 1->2(significa che Rporta il cubo dalla posizione iniziale del cubo 1alla posizione iniziale del cubo 2). Pertanto, Rpuò essere semplificato ulteriormente per un ciclo

Cycles[{{1,2,6,5}, {10,14,18,13}}]

Per risolvere completamente un cubo di Rubik, dobbiamo anche allineare i cubi ai loro corrispondenti orientamenti iniziali. Le facce di un cubo sono dipinte in diversi colori, lo schema che uso spesso quando risolvo i cubi è

face color
U    yellow
D    white
F    red
B    orange
R    green
L    blue

Quando analizziamo gli orientamenti degli angoli, i colori diversi dal giallo o dal bianco vengono ignorati e il giallo e il bianco sono considerati dello stesso colore.

Supponiamo che il cubo 1sia nella sua posizione iniziale UFR, la faccetta gialla può essere allineata a tre facce diverse. Usiamo un numero intero per rappresentare questi casi,

0  yellow on U  (correct)
1  yellow on R  (120 degree clockwise)
2  yellow on F  (120 degree counterclockwise)

Supponiamo che Cubie 1sia attivo DFL, i suoi tre possibili orientamenti sono

0  yellow on D  (correct)
1  yellow on L  (120 degree clockwise)
2  yellow on F  (120 degree counterclockwise)

Quando analizziamo gli orientamenti dei bordi, il rosso e l'arancione vengono ignorati e il giallo e il bianco vengono ignorati solo se il bordo ha una sfaccettatura verde o blu.

Supponiamo che il cubo 10sia nella sua posizione iniziale UR, la faccetta verde può essere allineata a due facce diverse. I suoi due possibili orientamenti sono

0  green on R  (correct)
1  green on U  (180 degree)

Supponiamo che Cubie 10sia attivo DF, i suoi due possibili orientamenti sono

0  green on D  (correct)
1  green on F  (180 degree)

Un array viene utilizzato per memorizzare lo stato di un cubo. Lo stato iniziale di un cubo è

{{1,0},{2,0},{3,0},{4,0},{5,0},{6,0},{7,0},{8,0},{9,0},{10,0},{11,0},{12,0},{13,0},{14,0},{15,0},{16,0},{17,0},{18,0},{19,0},{20,0}}

il che significa che ogni cubo è nella sua posizione iniziale con l'orientamento corretto.

Successivamente R, lo stato del cubo diventa

{{5,2},{1,1},{3,0},{4,0},{6,1},{2,2},{7,0},{8,0},{9,0},{13,1},{11,0},{12,0},{18,1},{10,1},{15,0},{16,0},{17,0},{14,1},{19,0},{20,0}}

il che significa che il cubo 5è ora in posizione 1( UFR) con orientamento 2, il cubo 1è ora in posizione 2( UBR) con orientamento 1, il cubo 3è ora ancora in posizione 3( UBL) con orientamento 0e così via.


Casi test

p["FF'"]            (* 1   *)
p["R"]              (* 4   *)
p["RUR'U'"]         (* 6   *)
p["LLUUFFUURRUU"]   (* 12  *)
p["LUFFRDRBF"]      (* 56  *)
p["LF"]             (* 105 *)
p["UFFR'DBBRL'"]    (* 120 *)
p["FRBL"]           (* 315 *)

7

Haskell, 252 byte

r=[-2..2]
s=mapM id[r,r,r]
t m p@[x,y,z]=case m of"R"|x>0->[x,z,-y];"L"|x<0->[x,-z,y];"U"|y>0->[-z,y,x];"D"|y<0->[z,y,-x];"F"|z>0->[y,-x,z];"B"|z<0->[-y,x,z];c:"'"->t[c]$t[c]$t[c]p;_->p
f m=length$s:fst(span(/=s)$tail$iterate(flip(foldl$flip$map.t)m)s)

Esecuzioni campione:

*Main> f ["F","F'"]
1
*Main> f ["R"]
4
*Main> f ["R","U","R'","U'"]
6
*Main> f ["L","L","U","U","F","F","U","U","R","R","U","U"]
12
*Main> f ["L","U","F","F","R","D","R","B","F"]
56
*Main> f ["L","F"]
105
*Main> f ["U","F","F","R'","D","B","B","R","L'"]
120
*Main> f ["F","R","B","L"]
315
*Main> f ["R","U","U","D'","B","D'"]  -- maximum possible order
1260

L'osservazione chiave qui è che è più semplice modellare il cubo di Rubik come una griglia di punti 5 × 5 × 5 piuttosto che una griglia di 3 × 3 × 3 di cubi orientati. I cubetti d'angolo diventano cubi di 2 × 2 × 2 punti, i cubetti di bordo diventano quadrati di 2 × 2 × 1 punti e le mosse ruotano sezioni di 5 × 5 × 2 punti.


Questo è davvero intelligente! Penso che la sostituzione c:"'"con c:_salva due byte.
Lynn,

Grazie! Stavo cercando una sequenza 1260 per i casi di test, ma non potevo preoccuparmi di cercarla :)
Geobits

@Lynn, non funziona perché _corrisponde anche alla lista vuota.
Anders Kaseorg,

Questo è fantastico, ma sembra molto simile a questa risposta a un'altra domanda codegolf.stackexchange.com/a/44775/15599 . Se sei stato ispirato da ciò, dovresti riconoscerlo.
Level River St,

@steveverrill, wow, sembra incredibilmente simile, ma no, non l'avevo visto. La mia risposta è il mio lavoro indipendente. (Riconosco, ovviamente, che Jan Dvorak ha avuto la maggior parte delle stesse idee prima di me.)
Anders Kaseorg

7

Rubino, 225 byte

->s{n=0
a=[]
b=[]
64.times{|i|a<<j=[(i&48)-16,(i&12)-4,i%4-1];b<<j*1}
d=1
(n+=1
s.reverse.chars{|c|m="UFRDBL".index(c)
m ?(e=m/3*2-1
b.each{|j|j[m%=3]*e>0&&(j[m-2],j[m-1]=j[m-1]*e*d,-j[m-2]*e*d)}
d=1):d=-1})until n>0&&a==b
n}

Simile alla risposta di Anders Kaseorg e ispirata di Jan Dvorak risposta ad una domanda precedente.

Tuttavia, a differenza di quelle risposte, non ho bisogno di 125 cubi. Uso un cubo di rubik di 27 cubetti, ma di dimensioni rettangolari. Nello stato risolto gli angoli sono a +/-1,+/-4,+/-16.

Genero una matrice di 64 cubi, ognuno con un centro scelto tra x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]. I cubetti con coordinate di 2, 8 e 32 non sono necessari, ma non danneggiano, quindi vengono lasciati per motivi di golf. Il fatto che lunghezza, larghezza e profondità dei cubetti siano diversi: (1,4,16) significa che è facile rilevare se si trovano nel posto giusto ma con orientamento errato.

Ogni cubo viene monitorato mentre viene spostato dai faceturns. Se la coordinata di un cubo nell'asse corrispondente alla faccia (moltiplicata per e=-1per U, F, R o e=1per D, B, L) è positiva, verrà ruotata scambiando le coordinate nell'altro 2 asse e applicando un segno appropriato cambia in una delle coordinate. Questo è controllato moltiplicando per e*d.

La sequenza di input viene scansionata in ordine inverso. Ciò non fa alcuna differenza, purché le rotazioni "normali" vengano eseguite in senso antiorario anziché orario. La ragione di ciò è che se 'viene trovato un simbolo, il valore di dpuò essere modificato da 1 a -1 per causare la rotazione della faccia seguente nella direzione opposta.

Non registrato nel programma di test

f=->s{n=0                                      #number of repeats=0
  a=[]                                         #empty array for solved position
  b=[]                                         #empty array for current position
  64.times{|i|
    a<<j=[(i&48)-16,(i&12)-4,i%4-1]            #generate 64 cubies and append them to the solved array
    b<<j*1                                     #duplicate them and append to active array
  }
  d=1                                          #default rotation direction anticlockwise (we scan the moves in reverse)                              
  (                                            #start of UNTIL loop
    n+=1                                       #increment repeat counter
    s.reverse.chars{|c|                        #reverse list of moves and iterate through it
      m="UFRDBL".index(c)                      #assign move letter to m (for ' or any other symbol m is false)
      m ?                                      #if a letter
        (e=m/3*2-1                             #e=-1 for UFR, 1 for DBL
        b.each{|j|                             #for each cubie 
          j[m%=3]*e>0&&                        #m%=3 picks an axis. If the cubie is on the moving face of the cube
         (j[m-2],j[m-1]=j[m-1]*e*d,-j[m-2]*e*d)#rotate it: exchange the coordinates in the other 2 axes and invert the sign of one of them according to direction
        }                                      #as per the values of e and d. 
        d=1                                    #set d=1 (in case it was -1 at the start of the b.each loop)
      ):
      d=-1                                     #ELSE the input must be a ', so set d=-1 to reverse rotation of next letter
    }
   )until n>0&&a==b                            #end of UNTIL loop. continue until back at start position a==b
n}                                             #return n

p f["FF'"]               #      1
p f["R"]                 #      4
p f["RUR'U'"]            #      6
p f["LLUUFFUURRUU"]      #     12
p f["LUFFRDRBF"]         #     56
p f["LF"]                #    105
p f["UFFR'DBBRL'"]       #    120
p f["FRBL"]              #    315

7

Python 2, 343 byte

def M(o,v,e):
 k=1
 for m in e:
  for c in'ouf|/[bPcU`Dkqbx-Y:(+=P4cyrh=I;-(:R6'[m::6]:i=~ord(c)%8*k;j=(ord(c)/8-4)*k;o[i],o[j]=o[j]-m/2,o[i]+m/2;v[i],v[j]=v[j],v[i];k=-k
V=range(20)
o,v,e=[0]*20,V[:],[]
for c in raw_input():i='FBRLUD'.find(c);e+=i<0and e[-1:]*2or[i]
M(o,v,e);n=1
while any(o[i]%(2+i/12)for i in V)or v>V:M(o,v,e);n+=1
print n

L'input è preso dallo stdin.

La sequenza data di colpi di scena viene eseguita ripetutamente su un cubo virtuale fino a quando non ritorna allo stato risolto. Lo stato del cubo viene memorizzato come vettore di orientamento e vettore di permutazione, entrambi di lunghezza 20.

Gli orientamenti sono definiti in qualche modo arbitrariamente: un cubie di bordi è orientato correttamente se può essere spostato in posizione senza invocare un quarto di giro di R o L. L'orientamento dei cubetti d'angolo è considerato relativo alle facce F e B.


Esempio di utilizzo

$ echo FRBL|python rubiks-cycle.py
315

$ echo RULURFLF|python rubiks-cycle.py
1260

Dimostrazione online e suite di test .


3
Buona scelta di nome e argomenti della funzione!
Neil,

3

Clojure, 359 byte

Questo potrebbe essere il mio secondo codegolf più lungo. Rendermi conto che avrei potuto eliminare gli zeri finali dai vettori Aper Frendermi molto felice: D

#(let[I(clojure.string/replace % #"(.)'""$1$1$1")D(range -2 3)S(for[x D y D z D][x y z])A[0 1]B[0 0 1]C[1]D[-1]E[0 -1]F[0 0 -1]](loop[P S[[n R]& Q](cycle(map{\F[A[B A D]]\B[E[F A C]]\L[D[C B E]]\R[C[C F A]]\U[B[E C B]]\D[F[A D B]]}I))c 0](if(=(> c 0)(= P S))(/ c(count I))(recur(for[p P](if(>(apply +(map * n p))0)(for[r R](apply +(map * r p)))p))Q(inc c)))))

Meno golf:

(def f #(let [I (clojure.string/replace % #"(.)'""$1$1$1")
              D [-2 -1 0 1 2]
              S (for[x D y D z D][x y z])
              L   {\F [[ 0  1  0][[0  0  1][ 0 1  0][-1  0 0]]]
                   \B [[ 0 -1  0][[0  0 -1][ 0 1  0][ 1  0 0]]]
                   \L [[-1  0  0][[1  0  0][ 0 0  1][ 0 -1 0]]]
                   \R [[ 1  0  0][[1  0  0][ 0 0 -1][ 0  1 0]]]
                   \U [[ 0  0  1][[0 -1  0][ 1 0  0][ 0  0 1]]]
                   \D [[ 0  0 -1][[0  1  0][-1 0  0][ 0  0 1]]]}]
          (loop [P S c 0 [[n R] & Q] (cycle(map L I))]
            (if (and (> c 0) (= P S))
              (/ c (count I))
              (recur (for[p P](if(pos?(apply +(map * n p)))
                                (for[r R](apply +(map * r p)))
                                p))
                     (inc c)
                     Q)))))

Questo implementa semplicemente le rotazioni 3D di sottoinsiemi di 5 x 5 x 5cubi selezionati . Inizialmente avrei usato 3 x 3 x 3e mi ci è voluto un po 'per capire perché non stavo ottenendo risultati corretti. Buoni casi di test! Alcuni byte extra per la codifica del pugno "RUR'U'"come "RURRRUUU".


3

Cubicamente , 9 6 byte

¶-7)8%

Provalo online! (Non funzionante fino a quando Dennis aggiorna l'interprete cubico TIO)

Spiegazione:

¶-7)8%
¶       read a string, insert into code
 -7     add 1 to notepad (subtracts the 7th face "sum" from notepad, defaulted to -1)
   )8   jump back to start of code if cube unsolved
     %  print notepad

Questa lingua dominerà tutte le sfide del >: D


3
Tutti questi esolang nuovi. -7
Ai

@cairdcoinheringaahing Infatti. : P Aggiunte alcune spiegazioni al riguardo.
MD XF,

1

Pulito , 255 byte

Derivato separatamente dalla risposta quasi identica di Haskell come risposta a questa domanda che è stata chiusa come duplicata quando era quasi finita, quindi ho pubblicato la risposta qui.

import StdEnv,StdLib
a=[-2..2];b=diag3 a a a
?m=iter(size m*2-1)\p=:(x,y,z)=case m.[0]of'F'|z>0=(y,~x,z);'U'|y>0=(~z,y,x);'R'|x>0=(x,z,~y);'B'|z<0=(~y,x,z);'D'|y<0=(z,y,~x);'L'|x<0=(x,~z,y);_=p
$l=length(takeWhile((<>)b)(tl(iterate(map(sseq(map?l)))b)))+1

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.