commit 2ecf0c214086916727b6ed7492513555dca312d9
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sun Jan 19 23:36:50 2020 +0000

    RubikCube: progress with scrambling

diff --git a/src/main/java/org/distorted/effect/ScrambleEffect.java b/src/main/java/org/distorted/effect/ScrambleEffect.java
index ea0380be..88089b0f 100644
--- a/src/main/java/org/distorted/effect/ScrambleEffect.java
+++ b/src/main/java/org/distorted/effect/ScrambleEffect.java
@@ -173,6 +173,11 @@ public abstract class ScrambleEffect implements EffectListener
       mNumScramblesLeft--;
       if( absAngle==2 ) mNumDoubleScramblesLeft--;
 
+      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
+        {
+        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
+        }
+
       mCurrentBaseEffectID = mCube.addNewRotation(mLastVector, row, angle*90, durationMillis, this );
       }
     else
@@ -182,11 +187,14 @@ public abstract class ScrambleEffect implements EffectListener
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO;
 
   private int randomizeAngle()
     {
-    return 1;
+    int random = mRnd.nextInt(mNumScramblesLeft);
+    int result = random<mNumDoubleScramblesLeft ? 2:1;
+    int sign   = mRnd.nextInt(2);
+
+    return sign==0 ? result : -result;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/effect/SolveEffect.java b/src/main/java/org/distorted/effect/SolveEffect.java
new file mode 100644
index 00000000..cad0d40f
--- /dev/null
+++ b/src/main/java/org/distorted/effect/SolveEffect.java
@@ -0,0 +1,242 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2019 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.effect;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+import org.distorted.library.effect.Effect;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedScreen;
+import org.distorted.library.message.EffectListener;
+import org.distorted.magic.RubikCube;
+
+import java.lang.reflect.Method;
+
+public abstract class SolveEffect implements EffectListener
+{
+  public enum Type
+    {
+    NONE   (SolveEffectNone.class),
+    SPIN   (SolveEffectSpin.class),
+    ;
+
+    final Class<? extends SolveEffect> effect;
+
+    Type(Class<? extends SolveEffect> effect)
+      {
+      this.effect = effect;
+      }
+    }
+
+  private static final int NUM_EFFECTS = Type.values().length;
+  private static final int NUM_PHASES  = 2;
+  private static final int FAKE_EFFECT_ID = -2;
+  private static final Type[] types;
+
+  static
+    {
+    int i=0;
+    types = new Type[NUM_EFFECTS];
+
+    for(Type type: Type.values())
+      {
+      types[i++] = type;
+      }
+    }
+
+  private EffectListener mListener;
+  private int mDuration;
+  private int mEffectReturned;
+  private int[] mCubeEffectNumber, mNodeEffectNumber;
+  private int mPhase;
+
+  RubikCube mCube;
+  DistortedScreen mScreen;
+  Effect[][] mCubeEffects;
+  int[][] mCubeEffectPosition;
+  Effect[][] mNodeEffects;
+  int[][] mNodeEffectPosition;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  SolveEffect()
+    {
+    mPhase        =  0;
+
+    mCubeEffectNumber   = new int[NUM_PHASES];
+    mNodeEffectNumber   = new int[NUM_PHASES];
+    mCubeEffectPosition = new int[NUM_PHASES][];
+    mNodeEffectPosition = new int[NUM_PHASES][];
+    mCubeEffects        = new Effect[NUM_PHASES][];
+    mNodeEffects        = new Effect[NUM_PHASES][];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static Type getType(int ordinal)
+    {
+    return types[ordinal];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static String[] getNames()
+    {
+    String[] names = new String[NUM_EFFECTS];
+
+    for( int i=0; i<NUM_EFFECTS; i++)
+      {
+      names[i] = types[i].name();
+      }
+
+    return names;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static SolveEffect create(Type type) throws InstantiationException, IllegalAccessException
+    {
+    return type.effect.newInstance();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  abstract void createEffectsPhase0(int duration);
+  abstract void createEffectsPhase1(int duration);
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void effectFinished(final long effectID)
+    {
+    int total = mCubeEffectNumber[mPhase]+mNodeEffectNumber[mPhase];
+
+    for(int i=0; i<mCubeEffectNumber[mPhase]; i++)
+      {
+      long id = mCubeEffects[mPhase][i].getID();
+
+      if( effectID == id )
+        {
+        if( ++mEffectReturned == total ) effectAction(mPhase);
+        mCube.remove(id);
+        return;
+        }
+      }
+    for(int i=0; i<mNodeEffectNumber[mPhase]; i++)
+      {
+      long id = mNodeEffects[mPhase][i].getID();
+
+      if( effectID == id )
+        {
+        if( ++mEffectReturned == total ) effectAction(mPhase);
+        mCube.getEffects().abortById(id);
+        return;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void effectAction(int phase)
+    {
+    switch(phase)
+      {
+      case 0: mEffectReturned = 0;
+              mPhase          = 1;
+              mCube.solve();
+              createEffectsPhase1(mDuration);
+              assignEffects(mPhase);
+              break;
+      case 1: mListener.effectFinished(FAKE_EFFECT_ID);
+              break;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public long start(int duration, DistortedScreen screen, RubikCube cube, EffectListener listener)
+    {
+    mScreen   = screen;
+    mCube     = cube;
+    mListener = listener;
+    mDuration = duration;
+
+    createEffectsPhase0(mDuration);
+    assignEffects(mPhase);
+
+    return FAKE_EFFECT_ID;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void assignEffects(int phase)
+    {
+    mCubeEffectNumber[phase] = ( mCubeEffects[phase]!=null ) ? mCubeEffects[phase].length : 0;
+    mNodeEffectNumber[phase] = ( mNodeEffects[phase]!=null ) ? mNodeEffects[phase].length : 0;
+
+    if( mCubeEffectNumber[phase]==0 && mNodeEffectNumber[phase]==0 )
+      {
+      throw new RuntimeException("Cube and Node Effects ("+phase+" phase) both not created!");
+      }
+
+    for(int i=0; i<mCubeEffectNumber[phase]; i++)
+      {
+      mCube.apply(mCubeEffects[phase][i],mCubeEffectPosition[phase][i]);
+      mCubeEffects[phase][i].notifyWhenFinished(this);
+      }
+
+    DistortedEffects nodeEffects = mCube.getEffects();
+
+    for(int i=0; i<mNodeEffectNumber[phase]; i++)
+      {
+      nodeEffects.apply(mNodeEffects[phase][i],mNodeEffectPosition[phase][i]);
+      mNodeEffects[phase][i].notifyWhenFinished(this);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @SuppressWarnings("unused")
+  public static void enableEffects()
+    {
+    Method method;
+
+    for(Type type: Type.values())
+      {
+      try
+        {
+        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
+        }
+      catch(NoSuchMethodException ex)
+        {
+        android.util.Log.e("SolveEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
+        method = null;
+        }
+
+      try
+        {
+        if( method!=null ) method.invoke(null);
+        }
+      catch(Exception ex)
+        {
+        android.util.Log.e("SolveEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
+        }
+      }
+    }
+}
diff --git a/src/main/java/org/distorted/effect/SolveEffectNone.java b/src/main/java/org/distorted/effect/SolveEffectNone.java
new file mode 100644
index 00000000..2f09aaea
--- /dev/null
+++ b/src/main/java/org/distorted/effect/SolveEffectNone.java
@@ -0,0 +1,61 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2019 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.effect;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+import org.distorted.library.effect.Effect;
+import org.distorted.library.effect.MatrixEffectMove;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Static3D;
+
+public class SolveEffectNone extends SolveEffect
+  {
+  public void createEffectsPhase0(int duration)
+    {
+    Dynamic3D d0 = new Dynamic3D(1,0.5f);
+    d0.add(new Static3D(0,0,0));
+
+    mCubeEffectPosition[0] = new int[] {-1};
+    mCubeEffects[0]        = new Effect[mCubeEffectPosition[0].length];
+    mCubeEffects[0][0]     = new MatrixEffectMove(d0);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void createEffectsPhase1(int duration)
+    {
+    Dynamic3D d0 = new Dynamic3D(1,0.5f);
+    d0.add(new Static3D(0,0,0));
+
+    mCubeEffectPosition[1]  = new int[] {-1};
+    mCubeEffects[1]         = new Effect[mCubeEffectPosition[1].length];
+    mCubeEffects[1][0]      = new MatrixEffectMove(d0);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Enable all effects used in this Effect. Called by reflection from the parent class.
+
+  @SuppressWarnings("unused")
+  static void enable()
+    {
+
+    }
+  }
diff --git a/src/main/java/org/distorted/effect/SolveEffectSpin.java b/src/main/java/org/distorted/effect/SolveEffectSpin.java
new file mode 100644
index 00000000..3ae430c9
--- /dev/null
+++ b/src/main/java/org/distorted/effect/SolveEffectSpin.java
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2019 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.effect;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+import org.distorted.library.effect.Effect;
+import org.distorted.library.effect.MatrixEffectRotate;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static3D;
+
+public class SolveEffectSpin extends SolveEffect
+  {
+  public void createEffectsPhase0(int duration)
+    {
+    mCubeEffectPosition[0] = new int[] {3};
+    mCubeEffects[0]        = new Effect[mCubeEffectPosition[0].length];
+
+    Static3D axis  = new Static3D(1,0,0);
+    Static3D center= new Static3D(0,0,0);
+
+    Dynamic1D d0 = new Dynamic1D(duration/2, 1.0f);
+    d0.setMode(Dynamic.MODE_JUMP);
+    d0.setConvexity(0.0f);          // otherwise speed of the rotation would be strangely uneven
+    d0.add(new Static1D( 0*36));
+    d0.add(new Static1D( 1*36));
+    d0.add(new Static1D( 3*36));
+    d0.add(new Static1D( 6*36));
+    d0.add(new Static1D(10*36));
+    mCubeEffects[0][0] = new MatrixEffectRotate(d0,axis,center);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void createEffectsPhase1(int duration)
+    {
+    mCubeEffectPosition[1] = new int[] {3};
+    mCubeEffects[1]        = new Effect[mCubeEffectPosition[1].length];
+
+    Static3D axis  = new Static3D(1,0,0);
+    Static3D center= new Static3D(0,0,0);
+
+    Dynamic1D d1 = new Dynamic1D(duration/2, 1.0f);
+    d1.setMode(Dynamic.MODE_JUMP);
+    d1.setConvexity(0.0f);
+    d1.add(new Static1D( 0*36));
+    d1.add(new Static1D( 4*36));
+    d1.add(new Static1D( 7*36));
+    d1.add(new Static1D( 9*36));
+    d1.add(new Static1D(10*36));
+    mCubeEffects[1][0] = new MatrixEffectRotate(d1,axis,center);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Enable all effects used in this Effect. Called by reflection from the parent class.
+
+  @SuppressWarnings("unused")
+  static void enable()
+    {
+
+    }
+  }
diff --git a/src/main/java/org/distorted/effect/UnscrambleEffect.java b/src/main/java/org/distorted/effect/UnscrambleEffect.java
deleted file mode 100644
index 6efdfb51..00000000
--- a/src/main/java/org/distorted/effect/UnscrambleEffect.java
+++ /dev/null
@@ -1,242 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2019 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.effect;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-import org.distorted.library.effect.Effect;
-import org.distorted.library.main.DistortedEffects;
-import org.distorted.library.main.DistortedScreen;
-import org.distorted.library.message.EffectListener;
-import org.distorted.magic.RubikCube;
-
-import java.lang.reflect.Method;
-
-public abstract class UnscrambleEffect implements EffectListener
-{
-  public enum Type
-    {
-    NONE   (UnscrambleEffectNone.class),
-    SPIN   (UnscrambleEffectSpin.class),
-    ;
-
-    final Class<? extends UnscrambleEffect> effect;
-
-    Type(Class<? extends UnscrambleEffect> effect)
-      {
-      this.effect = effect;
-      }
-    }
-
-  private static final int NUM_EFFECTS = Type.values().length;
-  private static final int NUM_PHASES  = 2;
-  private static final int FAKE_EFFECT_ID = -2;
-  private static final Type[] types;
-
-  static
-    {
-    int i=0;
-    types = new Type[NUM_EFFECTS];
-
-    for(Type type: Type.values())
-      {
-      types[i++] = type;
-      }
-    }
-
-  private EffectListener mListener;
-  private int mDuration;
-  private int mEffectReturned;
-  private int[] mCubeEffectNumber, mNodeEffectNumber;
-  private int mPhase;
-
-  RubikCube mCube;
-  DistortedScreen mScreen;
-  Effect[][] mCubeEffects;
-  int[][] mCubeEffectPosition;
-  Effect[][] mNodeEffects;
-  int[][] mNodeEffectPosition;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  UnscrambleEffect()
-    {
-    mPhase        =  0;
-
-    mCubeEffectNumber   = new int[NUM_PHASES];
-    mNodeEffectNumber   = new int[NUM_PHASES];
-    mCubeEffectPosition = new int[NUM_PHASES][];
-    mNodeEffectPosition = new int[NUM_PHASES][];
-    mCubeEffects        = new Effect[NUM_PHASES][];
-    mNodeEffects        = new Effect[NUM_PHASES][];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static Type getType(int ordinal)
-    {
-    return types[ordinal];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static String[] getNames()
-    {
-    String[] names = new String[NUM_EFFECTS];
-
-    for( int i=0; i<NUM_EFFECTS; i++)
-      {
-      names[i] = types[i].name();
-      }
-
-    return names;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static UnscrambleEffect create(Type type) throws InstantiationException, IllegalAccessException
-    {
-    return type.effect.newInstance();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  abstract void createEffectsPhase0(int duration);
-  abstract void createEffectsPhase1(int duration);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void effectFinished(final long effectID)
-    {
-    int total = mCubeEffectNumber[mPhase]+mNodeEffectNumber[mPhase];
-
-    for(int i=0; i<mCubeEffectNumber[mPhase]; i++)
-      {
-      long id = mCubeEffects[mPhase][i].getID();
-
-      if( effectID == id )
-        {
-        if( ++mEffectReturned == total ) effectAction(mPhase);
-        mCube.remove(id);
-        return;
-        }
-      }
-    for(int i=0; i<mNodeEffectNumber[mPhase]; i++)
-      {
-      long id = mNodeEffects[mPhase][i].getID();
-
-      if( effectID == id )
-        {
-        if( ++mEffectReturned == total ) effectAction(mPhase);
-        mCube.getEffects().abortById(id);
-        return;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void effectAction(int phase)
-    {
-    switch(phase)
-      {
-      case 0: mEffectReturned = 0;
-              mPhase          = 1;
-              mCube.unscramble();
-              createEffectsPhase1(mDuration);
-              assignEffects(mPhase);
-              break;
-      case 1: mListener.effectFinished(FAKE_EFFECT_ID);
-              break;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public long start(int duration, DistortedScreen screen, RubikCube cube, EffectListener listener)
-    {
-    mScreen   = screen;
-    mCube     = cube;
-    mListener = listener;
-    mDuration = duration;
-
-    createEffectsPhase0(mDuration);
-    assignEffects(mPhase);
-
-    return FAKE_EFFECT_ID;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void assignEffects(int phase)
-    {
-    mCubeEffectNumber[phase] = ( mCubeEffects[phase]!=null ) ? mCubeEffects[phase].length : 0;
-    mNodeEffectNumber[phase] = ( mNodeEffects[phase]!=null ) ? mNodeEffects[phase].length : 0;
-
-    if( mCubeEffectNumber[phase]==0 && mNodeEffectNumber[phase]==0 )
-      {
-      throw new RuntimeException("Cube and Node Effects ("+phase+" phase) both not created!");
-      }
-
-    for(int i=0; i<mCubeEffectNumber[phase]; i++)
-      {
-      mCube.apply(mCubeEffects[phase][i],mCubeEffectPosition[phase][i]);
-      mCubeEffects[phase][i].notifyWhenFinished(this);
-      }
-
-    DistortedEffects nodeEffects = mCube.getEffects();
-
-    for(int i=0; i<mNodeEffectNumber[phase]; i++)
-      {
-      nodeEffects.apply(mNodeEffects[phase][i],mNodeEffectPosition[phase][i]);
-      mNodeEffects[phase][i].notifyWhenFinished(this);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @SuppressWarnings("unused")
-  public static void enableEffects()
-    {
-    Method method;
-
-    for(Type type: Type.values())
-      {
-      try
-        {
-        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
-        }
-      catch(NoSuchMethodException ex)
-        {
-        android.util.Log.e("UnscrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
-        method = null;
-        }
-
-      try
-        {
-        if( method!=null ) method.invoke(null);
-        }
-      catch(Exception ex)
-        {
-        android.util.Log.e("UnscrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
-        }
-      }
-    }
-}
diff --git a/src/main/java/org/distorted/effect/UnscrambleEffectNone.java b/src/main/java/org/distorted/effect/UnscrambleEffectNone.java
deleted file mode 100644
index 1913e5ba..00000000
--- a/src/main/java/org/distorted/effect/UnscrambleEffectNone.java
+++ /dev/null
@@ -1,61 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2019 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.effect;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-import org.distorted.library.effect.Effect;
-import org.distorted.library.effect.MatrixEffectMove;
-import org.distorted.library.type.Dynamic3D;
-import org.distorted.library.type.Static3D;
-
-public class UnscrambleEffectNone extends UnscrambleEffect
-  {
-  public void createEffectsPhase0(int duration)
-    {
-    Dynamic3D d0 = new Dynamic3D(1,0.5f);
-    d0.add(new Static3D(0,0,0));
-
-    mCubeEffectPosition[0] = new int[] {-1};
-    mCubeEffects[0]        = new Effect[mCubeEffectPosition[0].length];
-    mCubeEffects[0][0]     = new MatrixEffectMove(d0);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void createEffectsPhase1(int duration)
-    {
-    Dynamic3D d0 = new Dynamic3D(1,0.5f);
-    d0.add(new Static3D(0,0,0));
-
-    mCubeEffectPosition[1]  = new int[] {-1};
-    mCubeEffects[1]         = new Effect[mCubeEffectPosition[1].length];
-    mCubeEffects[1][0]      = new MatrixEffectMove(d0);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Enable all effects used in this Effect. Called by reflection from the parent class.
-
-  @SuppressWarnings("unused")
-  static void enable()
-    {
-
-    }
-  }
diff --git a/src/main/java/org/distorted/effect/UnscrambleEffectSpin.java b/src/main/java/org/distorted/effect/UnscrambleEffectSpin.java
deleted file mode 100644
index a9f27e30..00000000
--- a/src/main/java/org/distorted/effect/UnscrambleEffectSpin.java
+++ /dev/null
@@ -1,81 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2019 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.effect;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-import org.distorted.library.effect.Effect;
-import org.distorted.library.effect.MatrixEffectRotate;
-import org.distorted.library.type.Dynamic;
-import org.distorted.library.type.Dynamic1D;
-import org.distorted.library.type.Static1D;
-import org.distorted.library.type.Static3D;
-
-public class UnscrambleEffectSpin extends UnscrambleEffect
-  {
-  public void createEffectsPhase0(int duration)
-    {
-    mCubeEffectPosition[0] = new int[] {3};
-    mCubeEffects[0]        = new Effect[mCubeEffectPosition[0].length];
-
-    Static3D axis  = new Static3D(1,0,0);
-    Static3D center= new Static3D(0,0,0);
-
-    Dynamic1D d0 = new Dynamic1D(duration/2, 1.0f);
-    d0.setMode(Dynamic.MODE_JUMP);
-    d0.setConvexity(0.0f);          // otherwise speed of the rotation would be strangely uneven
-    d0.add(new Static1D( 0*36));
-    d0.add(new Static1D( 1*36));
-    d0.add(new Static1D( 3*36));
-    d0.add(new Static1D( 6*36));
-    d0.add(new Static1D(10*36));
-    mCubeEffects[0][0] = new MatrixEffectRotate(d0,axis,center);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void createEffectsPhase1(int duration)
-    {
-    mCubeEffectPosition[1] = new int[] {3};
-    mCubeEffects[1]        = new Effect[mCubeEffectPosition[1].length];
-
-    Static3D axis  = new Static3D(1,0,0);
-    Static3D center= new Static3D(0,0,0);
-
-    Dynamic1D d1 = new Dynamic1D(duration/2, 1.0f);
-    d1.setMode(Dynamic.MODE_JUMP);
-    d1.setConvexity(0.0f);
-    d1.add(new Static1D( 0*36));
-    d1.add(new Static1D( 4*36));
-    d1.add(new Static1D( 7*36));
-    d1.add(new Static1D( 9*36));
-    d1.add(new Static1D(10*36));
-    mCubeEffects[1][0] = new MatrixEffectRotate(d1,axis,center);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Enable all effects used in this Effect. Called by reflection from the parent class.
-
-  @SuppressWarnings("unused")
-  static void enable()
-    {
-
-    }
-  }
diff --git a/src/main/java/org/distorted/magic/RubikActivity.java b/src/main/java/org/distorted/magic/RubikActivity.java
index eaa0105b..d92b18e9 100644
--- a/src/main/java/org/distorted/magic/RubikActivity.java
+++ b/src/main/java/org/distorted/magic/RubikActivity.java
@@ -32,7 +32,7 @@ import android.view.View;
 import org.distorted.component.HorizontalNumberPicker;
 import org.distorted.effect.ScrambleEffect;
 import org.distorted.effect.SizeChangeEffect;
-import org.distorted.effect.UnscrambleEffect;
+import org.distorted.effect.SolveEffect;
 import org.distorted.library.main.DistortedLibrary;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -44,10 +44,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
     private static final int[] button_ids  = {R.id.rubikSize2, R.id.rubikSize3, R.id.rubikSize4};
 
     public static final int DEFAULT_SIZECHANGE_POS = 20;
-    public static final int DEFAULT_UNSCRAMBLE_POS = 20;
+    public static final int DEFAULT_SOLVE_POS      = 20;
     public static final int DEFAULT_SCRAMBLE_POS   =100;
     public static final int DEFAULT_SIZECHANGE_TYPE= 1;
-    public static final int DEFAULT_UNSCRAMBLE_TYPE= 1;
+    public static final int DEFAULT_SOLVE_TYPE     = 1;
     public static final int DEFAULT_SCRAMBLE_TYPE  = 0;
 
     public static final int MIN_SCRAMBLE =  1;
@@ -55,8 +55,8 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
 
     private static int mSize = DEFAULT_SIZE;
 
-    private int mSizeChangePos, mUnscramblePos, mScramblePos;
-    private int mSizeChangeType, mUnscrambleType, mScrambleType;
+    private int mSizeChangePos, mSolvePos, mScramblePos;
+    private int mSizeChangeType, mSolveType, mScrambleType;
 
     private HorizontalNumberPicker mPicker;
 
@@ -123,10 +123,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
       Bundle args = new Bundle();
 
       args.putInt("sizechangePos" , mSizeChangePos );
-      args.putInt("unscramblePos" , mUnscramblePos );
+      args.putInt("solvePos"      , mSolvePos      );
       args.putInt("scramblePos"   , mScramblePos   );
       args.putInt("sizechangeType", mSizeChangeType);
-      args.putInt("unscrambleType", mUnscrambleType);
+      args.putInt("solveType"     , mSolveType     );
       args.putInt("scrambleType"  , mScrambleType  );
 
       RubikSettings settings = new RubikSettings();
@@ -154,10 +154,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void Unscramble(View v)
+    public void Solve(View v)
       {
       RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
-      view.getRenderer().unscrambleCube();
+      view.getRenderer().solveCube();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -165,10 +165,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
     public void onComplete(int sizeP, int unscP, int scraP, int sizeT, int unscT, int scraT )
       {
       mSizeChangePos = sizeP;
-      mUnscramblePos = unscP;
+      mSolvePos      = unscP;
       mScramblePos   = scraP;
       mSizeChangeType= sizeT;
-      mUnscrambleType= unscT;
+      mSolveType     = unscT;
       mScrambleType  = scraT;
 
       applyPreferences();
@@ -225,10 +225,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
      SharedPreferences.Editor editor = preferences.edit();
 
      editor.putInt("sizechangePos" , mSizeChangePos );
-     editor.putInt("unscramblePos" , mUnscramblePos );
+     editor.putInt("solvePos"      , mSolvePos      );
      editor.putInt("scramblePos"   , mScramblePos   );
      editor.putInt("sizechangeType", mSizeChangeType);
-     editor.putInt("unscrambleType", mUnscrambleType);
+     editor.putInt("solveType"     , mSolveType     );
      editor.putInt("scrambleType"  , mScrambleType  );
      editor.putInt("scramble"      , mPicker.getValue() );
 
@@ -242,10 +242,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
      SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
 
      mSizeChangePos = preferences.getInt("sizechangePos" , DEFAULT_SIZECHANGE_POS );
-     mUnscramblePos = preferences.getInt("unscramblePos" , DEFAULT_UNSCRAMBLE_POS );
+     mSolvePos      = preferences.getInt("solvePos"      , DEFAULT_SOLVE_POS      );
      mScramblePos   = preferences.getInt("scramblePos"   , DEFAULT_SCRAMBLE_POS   );
      mSizeChangeType= preferences.getInt("sizechangeType", DEFAULT_SIZECHANGE_TYPE);
-     mUnscrambleType= preferences.getInt("unscrambleType", DEFAULT_UNSCRAMBLE_TYPE);
+     mSolveType     = preferences.getInt("solveType"     , DEFAULT_SOLVE_TYPE     );
      mScrambleType  = preferences.getInt("scrambleType"  , DEFAULT_SCRAMBLE_TYPE  );
      int scramble   = preferences.getInt("scramble"      , MIN_SCRAMBLE           );
 
@@ -260,10 +260,10 @@ public class RubikActivity extends AppCompatActivity implements RubikSettings.On
      RubikRenderer renderer = view.getRenderer();
 
      renderer.setSizeChangeDuration(translateDuration(mSizeChangePos)+1);
-     renderer.setUnscrambleDuration(translateDuration(mUnscramblePos)+1);
+     renderer.setSolveDuration(translateDuration(mSolvePos)+1);
      renderer.setScrambleDuration(translateDuration(mScramblePos)+1);
      renderer.setSizeChangeType(SizeChangeEffect.getType(mSizeChangeType));
-     renderer.setUnscrambleType(UnscrambleEffect.getType(mUnscrambleType));
+     renderer.setSolveType(SolveEffect.getType(mSolveType));
      renderer.setScrambleType(ScrambleEffect.getType(mScrambleType));
      }
 
diff --git a/src/main/java/org/distorted/magic/RubikCube.java b/src/main/java/org/distorted/magic/RubikCube.java
index d741b527..b02bed62 100644
--- a/src/main/java/org/distorted/magic/RubikCube.java
+++ b/src/main/java/org/distorted/magic/RubikCube.java
@@ -217,7 +217,7 @@ public class RubikCube extends DistortedNode
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void unscramble()
+    public void solve()
       {
       for(int x=0; x<mSize; x++)
         for(int y=0; y<mSize; y++)
diff --git a/src/main/java/org/distorted/magic/RubikRenderer.java b/src/main/java/org/distorted/magic/RubikRenderer.java
index c259b458..56c03f11 100644
--- a/src/main/java/org/distorted/magic/RubikRenderer.java
+++ b/src/main/java/org/distorted/magic/RubikRenderer.java
@@ -22,7 +22,7 @@ package org.distorted.magic;
 import android.opengl.GLSurfaceView;
 
 import org.distorted.effect.SizeChangeEffect;
-import org.distorted.effect.UnscrambleEffect;
+import org.distorted.effect.SolveEffect;
 import org.distorted.effect.ScrambleEffect;
 import org.distorted.library.effect.VertexEffectSink;
 import org.distorted.library.main.DistortedEffects;
@@ -50,16 +50,16 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
     private Static4D mTempCurrent, mTempAccumulated;
     private float mCubeSizeInScreenSpace;
     private int mNextCubeSize, mScrambleCubeNum;
-    private long mRotationFinishedID, mSizeChangeEffectID, mUnscrambleEffectID, mScrambleEffectID;
+    private long mRotationFinishedID, mSizeChangeEffectID, mSolveEffectID, mScrambleEffectID;
     private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated, mSolveCube, mScrambleCube;
-    private boolean mCanRotate, mCanDrag;
+    private boolean mCanRotate, mCanDrag, mCanScramble, mCanSolve;
     private RubikCube mOldCube, mNewCube;
     private int mScreenWidth, mScreenHeight;
     private MeshFlat mMesh;
     private SizeChangeEffect.Type mSizeChangeType;
-    private UnscrambleEffect.Type mUnscrambleType;
+    private SolveEffect.Type mSolveType;
     private ScrambleEffect.Type mScrambleType;
-    private int mSizeChangeDuration, mUnscrambleDuration, mScrambleDuration;
+    private int mSizeChangeDuration, mSolveDuration, mScrambleDuration;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -87,15 +87,17 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
       mSolveCube             = false;
       mScrambleCube          = false;
 
-      mCanRotate = true;
-      mCanDrag   = true;
+      mCanRotate   = true;
+      mCanDrag     = true;
+      mCanScramble = true;
+      mCanSolve    = true;
 
-      mSizeChangeType    = SizeChangeEffect.Type.TRANSPARENCY;
-      mUnscrambleType    = UnscrambleEffect.Type.SPIN;
-      mScrambleType      = ScrambleEffect.Type.NONE;
+      mSizeChangeType= SizeChangeEffect.Type.TRANSPARENCY;
+      mSolveType     = SolveEffect.Type.SPIN;
+      mScrambleType  = ScrambleEffect.Type.NONE;
 
       mSizeChangeDuration= 1000;
-      mUnscrambleDuration= 1000;
+      mSolveDuration     = 1000;
       mScrambleDuration  = 1000;
 
       mMesh= new MeshFlat(20,20);
@@ -150,10 +152,12 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
       if( mSolveCube )
         {
-        mSolveCube = false;
-        mCanDrag   = false;
-        mCanRotate = false;
-        unscrambleCubeNow();
+        mSolveCube   = false;
+        mCanDrag     = false;
+        mCanRotate   = false;
+        mCanScramble = false;
+        mCanSolve    = false;
+        solveCubeNow();
         }
 
       if( mScrambleCube )
@@ -161,6 +165,8 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
         mScrambleCube = false;
         mCanDrag      = false;
         mCanRotate    = false;
+        mCanScramble  = false;
+        mCanSolve     = false;
         scrambleCubeNow();
         }
       }
@@ -194,7 +200,7 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
       VertexEffectSink.enable();
       SizeChangeEffect.enableEffects();
       ScrambleEffect.enableEffects();
-      UnscrambleEffect.enableEffects();
+      SolveEffect.enableEffects();
 
       try
         {
@@ -210,24 +216,28 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
    public void effectFinished(final long effectID)
      {
-     if(      effectID == mRotationFinishedID        )
+     if(      effectID == mRotationFinishedID )
        {
        mRemoveRotation = true;
        }
-     else if( effectID == mSizeChangeEffectID        )
+     else if( effectID == mSizeChangeEffectID )
        {
-       mCanRotate = true;
-       mCanDrag   = true;
+       mCanRotate   = true;
+       mCanDrag     = true;
        }
-     else if( effectID == mUnscrambleEffectID        )
+     else if( effectID == mSolveEffectID )
        {
-       mCanRotate = true;
-       mCanDrag   = true;
+       mCanRotate   = true;
+       mCanDrag     = true;
+       mCanSolve    = true;
+       mCanScramble = true;
        }
-     else if( effectID == mScrambleEffectID          )
+     else if( effectID == mScrambleEffectID   )
        {
-       mCanRotate = true;
-       mCanDrag   = true;
+       mCanRotate   = true;
+       mCanDrag     = true;
+       mCanSolve    = true;
+       mCanScramble = true;
        }
      }
 
@@ -276,9 +286,9 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   void setUnscrambleDuration(int duration)
+   void setSolveDuration(int duration)
      {
-     mUnscrambleDuration = duration;
+     mSolveDuration = duration;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -297,9 +307,9 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   void setUnscrambleType(UnscrambleEffect.Type type)
+   void setSolveType(SolveEffect.Type type)
      {
-     mUnscrambleType = type;
+     mSolveType = type;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -357,8 +367,11 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
    void scrambleCube(int num)
      {
-     mScrambleCube = true;
-     mScrambleCubeNum = num;
+     if( mCanScramble )
+       {
+       mScrambleCube = true;
+       mScrambleCubeNum = num;
+       }
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -381,27 +394,30 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   void unscrambleCube()
+   void solveCube()
      {
-     mSolveCube = true;
+     if( mCanSolve )
+       {
+       mSolveCube = true;
+       }
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   private void unscrambleCubeNow()
+   private void solveCubeNow()
      {
      try
        {
-       UnscrambleEffect effect = UnscrambleEffect.create(mUnscrambleType);
-       mUnscrambleEffectID = effect.start(mUnscrambleDuration,mScreen,mNewCube,this);
+       SolveEffect effect = SolveEffect.create(mSolveType);
+       mSolveEffectID = effect.start(mSolveDuration,mScreen,mNewCube,this);
        }
      catch(Exception ex)
        {
-       android.util.Log.e("Renderer", "failed to create UnscrambleEffect, exception: "+ex.getMessage());
+       android.util.Log.e("Renderer", "failed to create SolveEffect, exception: "+ex.getMessage());
 
-       mNewCube.unscramble();    //
-       mCanRotate = true;        // just unscramble the cube
-       mCanDrag   = true;        //
+       mNewCube.solve();    //
+       mCanRotate = true;   // just solve the cube
+       mCanDrag   = true;   //
        }
      }
 
diff --git a/src/main/java/org/distorted/magic/RubikSettings.java b/src/main/java/org/distorted/magic/RubikSettings.java
index 0e9f5879..9bff4e36 100644
--- a/src/main/java/org/distorted/magic/RubikSettings.java
+++ b/src/main/java/org/distorted/magic/RubikSettings.java
@@ -37,7 +37,7 @@ import android.widget.Spinner;
 import android.widget.TextView;
 
 import org.distorted.effect.SizeChangeEffect;
-import org.distorted.effect.UnscrambleEffect;
+import org.distorted.effect.SolveEffect;
 import org.distorted.effect.ScrambleEffect;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -50,9 +50,9 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
     }
 
   private OnCompleteListener mListener;
-  private int mSizeChangePos, mUnscramblePos, mScramblePos;
-  private int mSizeChangeType, mUnscrambleType, mScrambleType;
-  private TextView mSizeChangeDuration, mUnscrambleDuration, mScrambleDuration;
+  private int mSizeChangePos, mSolvePos, mScramblePos;
+  private int mSizeChangeType, mSolveType, mScrambleType;
+  private TextView mSizeChangeDuration, mSolveDuration, mScrambleDuration;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -83,19 +83,19 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
     try
       {
       mSizeChangePos = args.getInt("sizechangePos");
-      mUnscramblePos = args.getInt("unscramblePos");
+      mSolvePos      = args.getInt("solvePos");
       mScramblePos   = args.getInt("scramblePos");
       mSizeChangeType= args.getInt("sizechangeType");
-      mUnscrambleType= args.getInt("unscrambleType");
+      mSolveType     = args.getInt("solveType");
       mScrambleType  = args.getInt("scrambleType");
       }
     catch(NullPointerException ex)
       {
       mSizeChangePos = RubikActivity.DEFAULT_SIZECHANGE_POS;
-      mUnscramblePos = RubikActivity.DEFAULT_UNSCRAMBLE_POS;
+      mSolvePos      = RubikActivity.DEFAULT_SOLVE_POS;
       mScramblePos   = RubikActivity.DEFAULT_SCRAMBLE_POS;
       mSizeChangeType= RubikActivity.DEFAULT_SIZECHANGE_TYPE;
-      mUnscrambleType= RubikActivity.DEFAULT_UNSCRAMBLE_TYPE;
+      mSolveType     = RubikActivity.DEFAULT_SOLVE_TYPE;
       mScrambleType  = RubikActivity.DEFAULT_SCRAMBLE_TYPE;
       }
     }
@@ -124,7 +124,7 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
     builder.setView(view);
 
     mSizeChangeDuration = view.findViewById(R.id.sizechangeDurationText);
-    mUnscrambleDuration = view.findViewById(R.id.unscrambleDurationText);
+    mSolveDuration      = view.findViewById(R.id.solveDurationText);
     mScrambleDuration   = view.findViewById(R.id.scrambleDurationText);
 
     /// SIZE CHANGE ///////////////////////////////////////////////////////
@@ -152,30 +152,30 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
     sizechangeBar.setOnSeekBarChangeListener(this);
     sizechangeBar.setProgress(mSizeChangePos);
 
-    /// UNSCRAMBLE ////////////////////////////////////////////////////////
-    Spinner unscrambleTypeSpinner  = view.findViewById(R.id.unscrambleType);
+    /// SOLVE /////////////////////////////////////////////////////////////
+    Spinner solveTypeSpinner  = view.findViewById(R.id.solveType);
 
-    if( unscrambleTypeSpinner!=null )
+    if( solveTypeSpinner!=null )
       {
-      unscrambleTypeSpinner.setOnItemSelectedListener(this);
-      String[] unscramble = UnscrambleEffect.getNames();
-      ArrayAdapter<String> adapterType = new ArrayAdapter<>(act,android.R.layout.simple_spinner_item, unscramble);
+      solveTypeSpinner.setOnItemSelectedListener(this);
+      String[] solve = SolveEffect.getNames();
+      ArrayAdapter<String> adapterType = new ArrayAdapter<>(act,android.R.layout.simple_spinner_item, solve);
       adapterType.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-      unscrambleTypeSpinner.setAdapter(adapterType);
+      solveTypeSpinner.setAdapter(adapterType);
 
-      if(mUnscrambleType>=0 && mUnscrambleType<unscramble.length)
+      if(mSolveType>=0 && mSolveType<solve.length)
         {
-        unscrambleTypeSpinner.setSelection(mUnscrambleType);
+        solveTypeSpinner.setSelection(mSolveType);
         }
       }
     else
       {
-      android.util.Log.e("dialog", "UNSCRAMBLE TYPE SPINNER NULL!!");
+      android.util.Log.e("dialog", "SOLVE TYPE SPINNER NULL!!");
       }
 
-    SeekBar unscrambleBar = view.findViewById(R.id.unscrambleDuration);
-    unscrambleBar.setOnSeekBarChangeListener(this);
-    unscrambleBar.setProgress(mUnscramblePos);
+    SeekBar solveBar = view.findViewById(R.id.solveDuration);
+    solveBar.setOnSeekBarChangeListener(this);
+    solveBar.setProgress(mSolvePos);
 
     /// SCRAMBLE //////////////////////////////////////////////////////////
     Spinner scrambleTypeSpinner  = view.findViewById(R.id.scrambleType);
@@ -209,7 +209,7 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
 
     private void saveOptions()
       {
-      mListener.onComplete(mSizeChangePos, mUnscramblePos, mScramblePos, mSizeChangeType, mUnscrambleType, mScrambleType);
+      mListener.onComplete(mSizeChangePos, mSolvePos, mScramblePos, mSizeChangeType, mSolveType, mScrambleType);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -219,7 +219,7 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
       switch(parent.getId())
         {
         case R.id.sizechangeType: mSizeChangeType= pos; break;
-        case R.id.unscrambleType: mUnscrambleType= pos; break;
+        case R.id.solveType     : mSolveType     = pos; break;
         case R.id.scrambleType  : mScrambleType  = pos; break;
         }
       }
@@ -234,9 +234,9 @@ public class RubikSettings extends AppCompatDialogFragment implements SeekBar.On
                                       int sizechange_ms= RubikActivity.translateDuration(mSizeChangePos);
                                       mSizeChangeDuration.setText(getString(R.string.ms_placeholder,sizechange_ms));
                                       break;
-        case R.id.unscrambleDuration: mUnscramblePos= progress;
-                                      int unscramble_ms= RubikActivity.translateDuration(mUnscramblePos);
-                                      mUnscrambleDuration.setText(getString(R.string.ms_placeholder,unscramble_ms));
+        case R.id.solveDuration     : mSolvePos= progress;
+                                      int solve_ms= RubikActivity.translateDuration(mSolvePos);
+                                      mSolveDuration.setText(getString(R.string.ms_placeholder,solve_ms));
                                       break;
         case R.id.scrambleDuration  : mScramblePos= progress;
                                       int scramble_ms= RubikActivity.translateDuration(mScramblePos);
diff --git a/src/main/res/layout/main.xml b/src/main/res/layout/main.xml
index 3e575952..2e74e049 100644
--- a/src/main/res/layout/main.xml
+++ b/src/main/res/layout/main.xml
@@ -83,7 +83,7 @@
             android:layout_width="wrap_content"
             android:layout_height="fill_parent"
             android:layout_weight="0.5"
-            android:onClick="Unscramble"
+            android:onClick="Solve"
             android:paddingLeft="5dp"
             android:paddingRight="5dp"
             android:text="@string/solve" />
diff --git a/src/main/res/layout/settings.xml b/src/main/res/layout/settings.xml
index 94db453e..42d37fe3 100644
--- a/src/main/res/layout/settings.xml
+++ b/src/main/res/layout/settings.xml
@@ -126,7 +126,7 @@
                 android:textAppearance="?android:attr/textAppearanceSmall" />
 
             <TextView
-                android:id="@+id/unscrambleDurationText"
+                android:id="@+id/solveDurationText"
                 android:layout_weight="0.2"
                 android:layout_width="0dp"
                 android:layout_height="fill_parent"
@@ -136,7 +136,7 @@
                 android:textAppearance="?android:attr/textAppearanceSmall" />
 
             <SeekBar
-                android:id="@+id/unscrambleDuration"
+                android:id="@+id/solveDuration"
                 android:layout_weight="0.6"
                 android:layout_width="0dp"
                 android:layout_height="fill_parent"
@@ -162,7 +162,7 @@
                 android:textAppearance="?android:attr/textAppearanceSmall" />
 
             <Spinner
-                android:id="@+id/unscrambleType"
+                android:id="@+id/solveType"
                 android:layout_weight="0.6"
                 android:layout_width="0dp"
                 android:layout_height="fill_parent"
