Faire du vélo avec Rubik

43

En faisant tourner mon cube de Rubik sans rien faire , mon fils a remarqué qu'il revenait constamment à l'état résolu. Je suis à peu près sûr qu'il pensait qu'il s'agissait d'une sorte de magie vaudou au début, mais je lui ai expliqué que si vous répétez la même séquence de mouvements, elle reviendra toujours à son état d'origine. Finalement.

Bien sûr, étant un enfant, il devait l'essayer lui-même et choisir une séquence "aléatoire" qui, selon lui, serait délicate. Il a perdu le fil après une dizaine de répétitions et m'a demandé combien de fois il devrait le répéter. Ne sachant pas la séquence qu'il utilisait, je lui ai dit que je ne le savais pas, mais que nous pourrions écrire un programme pour le découvrir.

C’est là que vous intervenez. Bien sûr, je pourrais simplement préparer quelque chose, mais il aimerait le taper lui-même. Il n’est pas encore très rapide comme dactylographe, alors j’ai besoin du programme le plus court possible .

Objectif

Avec une séquence de tours, affichez le moins de fois possible pour que le cube revienne à son état d'origine. C'est le code de golf, donc le moins d'octets gagne. Vous pouvez écrire un programme ou une fonction et appliquer toutes les autres valeurs par défaut habituelles.

Contribution

L'entrée est une séquence de mouvements, pris comme une chaîne, une liste ou tout autre format adapté à votre langue. N'hésitez pas à utiliser un séparateur (ou non) entre les déplacements si vous êtes sous forme de chaîne.

Il y a six mouvements "de base" qui doivent être pris en compte, ainsi que leurs inverses:

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

Les inverses sont représentés en ajoutant une marque principale 'après la lettre. Cela indique que vous tournez cette face dans le sens inverse des aiguilles d'une montre. Vous devez donc F'tourner la face avant dans le sens contraire des aiguilles d'une montre F F'pour rétablir immédiatement l'état d'origine.

Pour les intéressés, ce défi utilise un ensemble limité de notation Singmaster . Ruwix propose de jolies animations si vous souhaitez le voir en action.

Sortie

La sortie est simplement le nombre minimum de fois que la séquence d'entrée doit être effectuée.

Exemples

Input                Output

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

Voici un solveur (assez naïf) avec lequel comparer vos réponses, écrit en Java. Il accepte également les 2coups doubles (le quatrième cas est équivalent à 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;
        }
    }
}
Géobits
la source
"dans le sens des aiguilles d'une montre" signifie "dans le sens des aiguilles d'une montre quand vous y faites face", je suppose?
msh210
@ msh210 Correct.
Geobits
7
En ce qui concerne le pédantisme, je pense que vous devriez indiquer clairement que vous voulez le plus petit nombre qui soit suffisant. Sinon, je pourrais simplement sortir la taille du groupe et citer le théorème de Lagrange ...
Peter Taylor
2
@PeterTaylor Pedantry accepté.
Geobits
4
Je peux offrir une prime de 500 points pour une solution dans Shuffle. Pas encore sûr.
lirtosiast

Réponses:

16

Pyth, 66 63 octets

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

Essayez-le en ligne: Démonstration ou Suite de tests . Notez que le programme est un peu lent et que le compilateur en ligne ne peut pas calculer la réponse RU2D'BD'. Mais soyez assuré qu'il peut le calculer sur mon ordinateur portable en environ 12 secondes.

Le programme (accidentellement) accepte également les 2doubles mouvements.

Explication complète:

Brouillage d'analyse:

Je traiterai d’abord des notes principales 'dans les chaînes de saisie. Je remplace simplement ceux-ci par 3et la longueur de décodage de cette chaîne. Comme le format de décodage de Pyth nécessite le nombre devant le caractère, je inverse la chaîne au préalable. _r_Xz\'\39. Alors après, je l'inverse.

Décrivez l'état du cube résolu:

=Z"UDLRFBassigne la chaîne avec tous les 6 coups à Z.

Nous pouvons décrire un état de cube en décrivant l'emplacement de chaque morceau de cube. Par exemple, nous pouvons dire que le bord, qui devrait être à UL (haut-gauche) est actuellement à FR (avant-droit). Pour cela , je dois générer toutes les pièces du cube résolu: f!s}RTcZ2yZ. yZgénère tous les sous-ensembles possibles de "UDLRFB". Cela génère évidemment aussi le sous-ensemble "UDLRFB"et le sous-ensemble "UD". Le premier n'a aucun sens, car aucune pièce n'est visible des 6 côtés, et le second n'a aucun sens, puisqu'il n'y a pas de bord, visible du haut et du bas. . Par conséquent, je supprime tous les sous-ensembles contenant la sous-séquence "UD", "LR"ou "FB". Cela me donne les 27 pièces suivantes:

'', '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'

Cela inclut également la chaîne vide et les six chaînes d'une lettre. Nous pourrions les interpréter comme la pièce au milieu du cube et les 6 pièces centrales. Évidemment, ils ne sont pas nécessaires (puisqu'ils ne bougent pas), mais je les garde.

Faire quelques mouvements:

Je vais faire quelques traductions de chaîne pour effectuer un mouvement. Pour visualiser l’idée, regardez le coin dans URF. Qu'advient-il de cela quand je fais un Rdéménagement? L'autocollant sur le Uvisage se déplace vers le Bvisage, l'autocollant Fsur le Uvisage et l'autocollant sur le Rvisage reste sur le Rvisage. Nous pouvons dire que la pièce à URFse déplace à la position BRU. Ce modèle est vrai pour toutes les pièces du côté droit. Chaque sticker qui est sur le Fvisage se déplace vers le Uvisage quand un Rmouvement est effectué, chaque autocollant qui est sur le Uvisage se déplace vers le Bvisage, chaque autocollant sur les Bmouvements à Det chaque autocollant sur Dse déplaceF. Nous pouvons décoder les changements d'un Rmouvement en tant que FUBD.

Le code suivant génère tous les 6 codes nécessaires:

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

Et nous effectuons un déplacement Hvers l'état du cube Gcomme suit:

m.rW}[email protected]
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)

Comptez le nombre de répétitions:

Le reste est à peu près trivial. J'effectue simplement le brouillage d'entrée dans le cube résolu encore et encore jusqu'à atteindre une position que j'avais précédemment visitée.

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
Jakube
la source
13

GAP, 792 783 782 749 650 Octets

Cela à l'air de marcher. Si quelque chose ne va pas, faites le moi savoir.

Merci à @Lynn pour m'avoir suggéré de décomposer certains des mouvements primitifs.

Merci à @Neil d’avoir suggéré cela au lieu de l’ Inverse(X)utiliser X^3.

Exemple d'utilisation: 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;

Voici le code non-golfé avec quelques explications

  # 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;
Liam
la source
Chaque mouvement est une quatrième racine de l'identité, votre inversion n'est donc pas nécessaire.
Neil
Vous pouvez probablement remplacer 45par 5dans vos permutations et économiser trois octets.
Lynn
Un résultat de Benson que j'ai trouvé dans Singmaster, 1981 dit: "Soit A = RL⁻¹F²B²RL⁻¹, puis AUA = D." En fait, A:=R*L*L*L*F*F*B*B*R*L*L*L;D:=A*U*A;est plus court que votre définition de D(mais je ne peux pas le tester ...)
Lynn
GAP ne vous laisse-t-il pas vraiment écrire ^-1pour les inverses, BTW?
Lynn
Oui, j'ai totalement espéré utiliser ^ -1. Ce que je suppose, c'est à peu près la même chose que @Neil disait, à la différence de ^ 3 à la place (qui est en réalité le plus court). Aussi, oui, je pourrais décomposer les mouvements en d'autres mouvements, et je devrais être capable de sauver plusieurs octets en le faisant, il s'agirait simplement de trouver la décomposition la plus courte.
Liam
10

Mathematica, 413 401 octets

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

Des explications

Un Rubik's Cube est composé de 20 cubes mobiles (8 coins, 12 bords). Un numéro peut être attribué à chaque casier:

coins :

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

bords :

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

Notez que lorsque le cube est tordu, les cubes ne sont généralement plus sur leurs positions de départ. Par exemple, lorsque cela Rest fait, le groupe 1passe d' UFRune nouvelle position à une autre UBR.

Dans cette notation, un virage à 90 degrés peut être décrit par 8 mouvements de cubies. Par exemple, Rest décrit par

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

Étant donné que chaque casier a une position de départ unique, chaque position a un casier de départ unique. C'est-à-dire que la règle UFR->UBRest juste 1->2(signifie que cela Rprend le cube sur la position de départ de cubie 1à la position de départ de cubie 2). Ainsi, Rpeut être simplifié suite à un cycle

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

Pour résoudre complètement un cube de Rubik, nous devons également aligner les cubes sur leurs orientations de départ correspondantes. Les faces d’un cube sont peintes de différentes couleurs, le schéma que j’utilise souvent pour résoudre des cubes est

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

Lorsque nous analysons les orientations des coins, les couleurs autres que le jaune ou le blanc sont ignorées, et le jaune et le blanc sont considérés comme la même couleur.

Supposons que cubie 1soit sur sa position de départ UFR, la facette jaune peut être alignée sur trois faces différentes. Nous utilisons un entier pour représenter ces cas,

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

Supposons que cubie 1soit activé DFL, ses trois orientations possibles sont

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

Lorsque nous analysons les orientations des bords, le rouge et l’orange sont ignorés, et le jaune et le blanc ne sont ignorés que si le bord a une facette verte ou bleue.

Supposons que cubie 10soit sur sa position de départ UR, la facette verte peut être alignée sur deux faces différentes. Ses deux orientations possibles sont

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

Supposons que cubie 10soit activé DF, ses deux orientations possibles sont

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

Un tableau est utilisé pour stocker l'état d'un cube. L'état de départ d'un cube est

{{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}}

ce qui signifie que tous les cubes sont sur leur position de départ avec une orientation correcte.

Après R, l'état du cube devient

{{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}}

ce qui signifie que cubie 5est maintenant sur position 1( UFR) avec orientation 2, cubie 1est maintenant sur position 2( UBR) avec orientation 1, cubie 3est maintenant toujours sur position 3( UBL) avec orientation 0, et ainsi de suite.


Cas de 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 *)
njpipeorgan
la source
7

Haskell, 252 octets

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)

Échantillons:

*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'observation clé ici est qu'il est plus simple de modéliser le cube de Rubik sous la forme d'une grille de points 5 × 5 × 5 plutôt que d'une grille 3 × 3 × 3 de cubies orientés. Les cubes d'angle deviennent des cubes de 2 × 2 × 2 points, les cubes de bords deviennent des carrés de 2 × 2 × 1 points et des tranches de 5 × 5 × 2 en rotation.

Anders Kaseorg
la source
C'est vraiment malin! Je pense que remplacer c:"'"par c:_sauve deux octets.
Lynn
Merci! Je cherchais une séquence 1260 pour les cas de test, mais je ne pouvais pas être dérangé de le regarder :)
Geobits
@ Lynn, cela ne fonctionne pas car _correspond également à la liste vide.
Anders Kaseorg
C’est génial, mais cela ressemble beaucoup à cette réponse à une autre question codegolf.stackexchange.com/a/44775/15599 . Si cela vous inspire, vous devriez le reconnaître.
Level River St
@steveverrill, wow, ça a l'air incroyablement similaire, mais non, je ne l'avais pas vu. Ma réponse est mon propre travail indépendant. (Je reconnais, bien sûr, que Jan Dvorak est venu avec la plupart des mêmes idées avant moi.)
Anders Kaseorg
7

Ruby, 225 octets

->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}

Similaire à la réponse d'Anders Kaseorg et inspiré par la réponse de Jan Dvorak à une question précédente.

Cependant, contrairement à ces réponses, je n'ai pas besoin de 125 cubes. J'utilise un cube en rubik de 27 cubes, mais de dimensions rectangulaires. Dans l'état résolu, les coins sont à +/-1,+/-4,+/-16.

Je génère un tableau de 64 cubies, chacune avec un centre choisi x=[-1,0,1,2], y=[-4,0,4,8], z=[-16-0,16,32]. Les cubes avec des coordonnées de 2, 8 et 32 ​​ne sont pas nécessaires, mais ils ne font pas de mal, ils sont donc laissés à l'intérieur pour des raisons de golf. Le fait que les cubies aient une longueur, une largeur et une profondeur différentes (1,4,16) signifie qu'il est facile de détecter s'ils se trouvent au bon endroit mais dans la mauvaise orientation.

Chaque casier est suivi au fur et à mesure qu’il est déplacé par les équipes. Si la coordonnée d'un cube dans l'axe correspondant à la face (multipliée par e=-1pour U, F, R ou e=1pour D, B, L) est positive, elle sera pivotée en échangeant les coordonnées dans les 2 autres axes et en appliquant un signe approprié changer à l'une des coordonnées. Ceci est contrôlé en multipliant par e*d.

La séquence d'entrée est balayée dans l'ordre inverse. Cela ne fait aucune différence, tant que les rotations "normales" sont effectuées dans le sens inverse des aiguilles d'une montre et non dans le sens des aiguilles d'une montre. La raison en est que, si un 'symbole est trouvé, la valeur de dpeut être modifiée de 1 à -1 afin de provoquer la rotation de la face suivante dans le sens opposé.

Programme non 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
Level River St
la source
7

Python 2, 343 octets

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'entrée est prise de stdin.

La séquence de torsions donnée est exécutée de manière répétée sur un cube virtuel jusqu'à ce qu'il revienne à l'état résolu. L'état du cube est stocké en tant que vecteur d'orientation et vecteur de permutation, tous deux de longueur 20.

Les orientations sont définies de manière quelque peu arbitraire: un groupe de bord est correctement orienté s'il peut être déplacé sans invoquer un quart de tour R ou L. L'orientation des coins est considérée par rapport aux faces F et B.


Exemple d'utilisation

$ echo FRBL|python rubiks-cycle.py
315

$ echo RULURFLF|python rubiks-cycle.py
1260

Démonstration en ligne et suite de tests .

primo
la source
3
Beau choix de nom de fonction et d'arguments!
Neil
3

Clojure, 359 octets

Cela pourrait être mon deuxième plus long codegolf. Se rendant compte que je pouvais laisser tomber zéros de vecteurs Aà Fm'a rendu très heureux: 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)))))

Moins joué au 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)))))

Ceci implémente simplement des rotations 3D de sous-ensembles sélectionnés de 5 x 5 x 5cube. À l'origine, j'allais l'utiliser 3 x 3 x 3et il m'a fallu un certain temps pour comprendre pourquoi mes résultats n'étaient pas corrects. Bons cas de test! Certains octets supplémentaires pour l' encodage poing "RUR'U'"comme "RURRRUUU".

NikoNyrh
la source
3

Cubiquement , 9 à 6 octets

¶-7)8%

Essayez-le en ligne! (Non actif jusqu'à ce que Dennis mette à jour l'interprète TIO Cubiquement)

Explication:

¶-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

Cette langue dominera tous les >: D

MD XF
la source
3
Tous ces nouveaux esolangs. De retour dans ma journée, -7signifiait soustraire sept pas ajouter un en colère shakes walker
caird coinheringaahing
@cairdcoinheringaahing En effet. : P Ajout d'une explication autour de ça.
MD XF
1

Nettoyer , 255 octets

Dérivée séparément de la réponse presque identique de Haskell en réponse à cette question qui était fermée en double lorsqu'elle était presque terminée, j'ai donc posté la réponse ici.

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

Essayez-le en ligne!

Οurous
la source