commit 0021af5864213d2460d5c6d4e8e1fd4f7643392a
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Sep 2 22:44:07 2021 +0200

    Convert Square-2 to the new generic scrambling algorithm.
    
    In order to do it we need to introduce a third, artificial rotational axis - otherwise the algorithm would make it impossible to rotate the lower layer and immediatelly after - the upper.

diff --git a/src/main/java/org/distorted/objects/MovementSquare.java b/src/main/java/org/distorted/objects/MovementSquare.java
index 8be74804..d213e95e 100644
--- a/src/main/java/org/distorted/objects/MovementSquare.java
+++ b/src/main/java/org/distorted/objects/MovementSquare.java
@@ -39,7 +39,7 @@ class MovementSquare extends Movement
 
   MovementSquare()
     {
-    super(TwistySquare1.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistySquare.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistySquare.java b/src/main/java/org/distorted/objects/TwistySquare.java
index 957c98ab..cc0507c6 100644
--- a/src/main/java/org/distorted/objects/TwistySquare.java
+++ b/src/main/java/org/distorted/objects/TwistySquare.java
@@ -40,13 +40,18 @@ abstract class TwistySquare extends TwistyObject
   static final float SIN15 = (SQ6-SQ2)/4;
   static final float     X = 3*(2-SQ3)/2;
 
+  // The third, artificial axis is for the generic scrambling algorithm.
+  // Otherwise it wouldn't be possible to rotate the LO and UP layers
+  // consecutively.
+
   static final Static3D[] ROT_AXIS = new Static3D[]
     {
-      new Static3D(0,1,0),
-      new Static3D(COS15,0,SIN15)
+      new Static3D(0,+1,0),
+      new Static3D(COS15,0,SIN15),
+      new Static3D(0,-1,0),
     };
 
-  static final int[] BASIC_ANGLE = new int[] { 12,2 };
+  static final int[] BASIC_ANGLE = new int[] { 12,2,12 };
 
   static final int[] FACE_COLORS = new int[]
     {
@@ -210,7 +215,7 @@ abstract class TwistySquare extends TwistyObject
 
   float[][] getCuts(int numLayers)
     {
-    return new float[][] { {-0.5f,+0.5f}, {0.0f} };
+    return new float[][] { {-0.5f,+0.5f}, {0.0f}, {-0.5f,+0.5f} };
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistySquare2.java b/src/main/java/org/distorted/objects/TwistySquare2.java
index f4025bf1..f13aee89 100644
--- a/src/main/java/org/distorted/objects/TwistySquare2.java
+++ b/src/main/java/org/distorted/objects/TwistySquare2.java
@@ -23,6 +23,7 @@ import android.content.res.Resources;
 
 import org.distorted.helpers.ObjectShape;
 import org.distorted.helpers.ObjectSticker;
+import org.distorted.helpers.ScrambleState;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshSquare;
@@ -173,12 +174,33 @@ class TwistySquare2 extends TwistySquare
       }
     }
 
+  private int mCurrState;
+  private int mIndexExcluded;
+  private final ScrambleState[] mStates;
+  private int[][] mScrambleTable;
+  private int[] mNumOccurences;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   TwistySquare2(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
     {
     super(size, quat, texture, mesh, effects, moves, ObjectList.SQU2, res, scrWidth);
+
+    int[] SL_6 = new int[] { 0,1,1, 1,1,1, 0,1,1, 1,1,1, 0,1,1, 1,1,1, 0,1,1, 1,1,1, 0,1,1, 1,1,1, 0,1,1, 1,1,1};
+    int[] SL_1 = new int[] { 0,1,1, 1,1,1 };
+    int[] LO_2 = new int[] { 0,-5,2, 0,-4,2, 0,-3,2, 0,-2,2, 0,-1,2, 0,1,2, 0,2,2, 0,3,2, 0,4,2, 0,5,2, 0,5,2 };
+    int[] LO_3 = new int[] { 0,-5,3, 0,-4,3, 0,-3,3, 0,-2,3, 0,-1,3, 0,1,3, 0,2,3, 0,3,3, 0,4,3, 0,5,3, 0,5,3 };
+    int[] LO_4 = new int[] { 0,-5,4, 0,-4,4, 0,-3,4, 0,-2,4, 0,-1,4, 0,1,4, 0,2,4, 0,3,4, 0,4,4, 0,5,4, 0,5,4 };
+
+    mStates = new ScrambleState[]
+      {
+      new ScrambleState( new int[][] { LO_2, SL_6, LO_3 } ),  // 0
+      new ScrambleState( new int[][] { LO_2, null, LO_3 } ),  // SL
+      new ScrambleState( new int[][] { null, SL_1, LO_4 } ),  // LO
+      new ScrambleState( new int[][] { LO_4, SL_1, null } ),  // UP
+      new ScrambleState( new int[][] { null, SL_1, null } ),  // UL
+      };
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -290,55 +312,52 @@ class TwistySquare2 extends TwistySquare
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 
-  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
+  private void initializeScrambling()
     {
-    int layer, nextAngle;
+    int numLayers = getNumLayers();
+
+    if( mScrambleTable ==null )
+      {
+      mScrambleTable = new int[NUM_AXIS][numLayers];
+      }
+    if( mNumOccurences ==null )
+      {
+      int max=0;
+
+      for (ScrambleState mState : mStates)
+        {
+        int tmp = mState.getTotal(-1);
+        if (max < tmp) max = tmp;
+        }
 
-    if( curr==0 ) mLastRot = rnd.nextInt(4);
+      mNumOccurences = new int[max];
+      }
+
+    for(int i=0; i<NUM_AXIS; i++)
+      for(int j=0; j<numLayers; j++) mScrambleTable[i][j] = 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
 
-    switch(mLastRot)
+  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int totalScrambles)
+    {
+    if( curr==0 )
       {
-      case LAST_SL: layer = rnd.nextInt(2);
-                    nextAngle = rnd.nextInt(12)-6;
-
-                    if( nextAngle==0 )
-                      {
-                      layer = 1-layer;
-                      nextAngle = (2*rnd.nextInt(2)-1)*(rnd.nextInt(5)+1);
-                      }
-
-                    scramble[curr][0] = 0;
-                    scramble[curr][1] = 2*layer;
-                    scramble[curr][2] = nextAngle;
-                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
-                    break;
-      case LAST_LO:
-      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
-                    nextAngle = rnd.nextInt(12)-6;
-
-                    if( nextAngle!=0 )
-                      {
-                      scramble[curr][0] = 0;
-                      scramble[curr][1] = 2*layer;
-                      scramble[curr][2] = nextAngle;
-                      mLastRot = LAST_UL;
-                      }
-                    else
-                      {
-                      scramble[curr][0] = 1;
-                      scramble[curr][1] = rnd.nextInt(2);
-                      scramble[curr][2] = 1;
-                      mLastRot = LAST_SL;
-                      }
-                    break;
-      case LAST_UL: scramble[curr][0] = 1;
-                    scramble[curr][1] = rnd.nextInt(2);
-                    scramble[curr][2] = 1;
-                    mLastRot = LAST_SL;
-                    break;
+      mCurrState     = 0;
+      mIndexExcluded =-1;
+      initializeScrambling();
       }
+
+    int[] info= mStates[mCurrState].getRandom(rnd, mIndexExcluded, mScrambleTable, mNumOccurences);
+
+    scramble[curr][0] = info[0];
+    scramble[curr][1] = info[1];
+    scramble[curr][2] = info[2];
+
+    mCurrState     = info[3];
+    mIndexExcluded = info[0];
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
