commit 7f84a768ef8d99d460e4bf276793902e3d1dbe54
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Apr 6 01:34:58 2020 +0100

    Progress with the 3x3x3 Solver.
    
    Hopefully the only thing that remains to be done is to implement the RubikStateSolver.retCubeString().

diff --git a/src/main/java/org/distorted/patterns/RubikPattern.java b/src/main/java/org/distorted/patterns/RubikPattern.java
index a456e820..40c455f6 100644
--- a/src/main/java/org/distorted/patterns/RubikPattern.java
+++ b/src/main/java/org/distorted/patterns/RubikPattern.java
@@ -30,7 +30,7 @@ import static org.distorted.patterns.RubikPatternList.NUM_OBJECTS;
 
 public class RubikPattern
 {
-  private static final int DURATION_MILLIS = 800;
+  private static final int DURATION_MILLIS = 750;
 
   private int[] numCategories   = new int[NUM_OBJECTS];
   private int[] currentCategory = new int[NUM_OBJECTS];
@@ -217,20 +217,7 @@ public class RubikPattern
       numMove = moveStr.length()/4;
       moves   = new int[numMove][3];
       curMove = numMove;
-
-      int digit0, digit1, digit2;
-
-      for(int i=0; i<numMove; i++)
-        {
-        digit0 = moveStr.charAt(4*i+1)-'0';
-        digit1 = moveStr.charAt(4*i+2)-'0';
-        digit2 = moveStr.charAt(4*i+3)-'0';
-
-        moves[i][0] = (10*digit0+digit1)/32;
-        moves[i][1] = (10*digit0+digit1)%32;
-        moves[i][2] = 2-digit2;
-        }
-
+      parseMoves(moves,numMove,moveStr);
       moveStr = null;
       mInitialized = true;
       }
@@ -266,10 +253,10 @@ public class RubikPattern
       {
       if( !mInitialized ) initialize();
 
-      curMove++;
-
       if( mCanRotate )
         {
+        curMove++;
+
         if( curMove>numMove )
           {
           curMove= 0;
@@ -297,7 +284,6 @@ public class RubikPattern
       else
         {
         android.util.Log.e("pattern", "failed to make Move!");
-        curMove--;
         }
       }
 
@@ -307,10 +293,10 @@ public class RubikPattern
       {
       if( !mInitialized ) initialize();
 
-      curMove--;
-
       if( mCanRotate )
         {
+        curMove--;
+
         if( curMove<0 )
           {
           curMove=numMove;
@@ -338,7 +324,6 @@ public class RubikPattern
       else
         {
         android.util.Log.e("pattern", "failed to back Move!");
-        curMove++;
         }
       }
 
@@ -405,6 +390,24 @@ public class RubikPattern
     return mThis;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void parseMoves(int[][] result, int numMoves, String moves)
+    {
+    int digit0, digit1, digit2;
+
+    for(int i=0; i<numMoves; i++)
+      {
+      digit0 = moves.charAt(4*i+1)-'0';
+      digit1 = moves.charAt(4*i+2)-'0';
+      digit2 = moves.charAt(4*i+3)-'0';
+
+      result[i][0] = (10*digit0+digit1)/32;
+      result[i][1] = (10*digit0+digit1)%32;
+      result[i][2] = 2-digit2;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getNumCategories(int tab)
diff --git a/src/main/java/org/distorted/solvers/cube3/Search.java b/src/main/java/org/distorted/solvers/cube3/Search.java
index 54d59eab..dcdb0c10 100644
--- a/src/main/java/org/distorted/solvers/cube3/Search.java
+++ b/src/main/java/org/distorted/solvers/cube3/Search.java
@@ -159,10 +159,6 @@ public class Search {
 	 *@param timeOut
 	 *          defines the maximum computing time of the method in seconds. If it does not return with a solution, it returns with
 	 *          an error code.
-	 * 
-	 * @param useSeparator
-	 *          determines if a " . " separates the phase1 and phase2 parts of the solver string like in F' R B R L2 F .
-	 *          U2 U D for example.<br>
 	 * @return The solution string or an error code:<br>
 	 *         Error 1: There is not exactly one facelet of each colour<br>
 	 *         Error 2: Not all 12 edges exist exactly once<br>
@@ -177,8 +173,6 @@ public class Search {
 	    {
 		int s;
 
-		Log.d("solution", facelets);
-		
 		mInterrupted = false;
 		
 		// +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++
diff --git a/src/main/java/org/distorted/states/RubikStateSolution.java b/src/main/java/org/distorted/states/RubikStateSolution.java
index 6e9c6359..98b3398c 100644
--- a/src/main/java/org/distorted/states/RubikStateSolution.java
+++ b/src/main/java/org/distorted/states/RubikStateSolution.java
@@ -31,15 +31,22 @@ import android.widget.TextView;
 
 import org.distorted.main.R;
 import org.distorted.main.RubikActivity;
+import org.distorted.main.RubikPostRender;
 import org.distorted.objects.RubikObject;
+import org.distorted.patterns.RubikPattern;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class RubikStateSolution extends RubikStateAbstract
+public class RubikStateSolution extends RubikStateAbstract implements RubikPostRender.ActionFinishedListener
   {
+  private static final int DURATION_MILLIS = 750;
+
   private Button mBackButton;
   private ImageButton mPrevButton, mNextButton;
   private TextView mMovesText;
+  private int[][] mMoves;
+  private int mCurrMove, mNumMoves;
+  private boolean mCanRotate;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -99,7 +106,9 @@ public class RubikStateSolution extends RubikStateAbstract
       @Override
       public void onClick(View v)
         {
-
+        RubikPostRender post = act.getPostRender();
+        backMove(post);
+        mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
         }
       });
     }
@@ -120,7 +129,9 @@ public class RubikStateSolution extends RubikStateAbstract
       @Override
       public void onClick(View v)
         {
-
+        RubikPostRender post = act.getPostRender();
+        makeMove(post);
+        mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
         }
       });
     }
@@ -137,7 +148,7 @@ public class RubikStateSolution extends RubikStateAbstract
     mMovesText.setLayoutParams(params);
     mMovesText.setPadding(padding,0,padding,0);
     mMovesText.setGravity(Gravity.CENTER);
-    mMovesText.setText(act.getString(R.string.mo_placeholder,0,0));
+    mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -161,6 +172,98 @@ public class RubikStateSolution extends RubikStateAbstract
       });
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void makeMove(RubikPostRender post)
+    {
+    if( mCanRotate )
+      {
+      mCurrMove++;
+
+      if( mCurrMove>mNumMoves )
+        {
+        mCurrMove= 0;
+        post.initializeObject(null);
+        }
+      else
+        {
+        int axis     = mMoves[mCurrMove-1][0];
+		    int rowBitmap= mMoves[mCurrMove-1][1];
+		    int bareAngle= mMoves[mCurrMove-1][2];
+        int angle    = bareAngle*(360/post.getObject().getBasicAngle());
+        int numRot   = Math.abs(bareAngle);
+
+        if( angle!=0 )
+          {
+          mCanRotate = false;
+          post.addRotation(this, axis, rowBitmap, angle, numRot*DURATION_MILLIS);
+          }
+        else
+          {
+          android.util.Log.e("solution", "error: solution contains angle 0");
+          }
+        }
+      }
+    else
+      {
+      android.util.Log.e("solution", "failed to make move!");
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void backMove(RubikPostRender post)
+    {
+    if( mCanRotate )
+      {
+      mCurrMove--;
+
+      if( mCurrMove<0 )
+        {
+        mCurrMove=mNumMoves;
+        post.initializeObject(mMoves);
+        }
+      else
+        {
+        int axis     = mMoves[mCurrMove][0];
+		    int rowBitmap= mMoves[mCurrMove][1];
+		    int bareAngle= mMoves[mCurrMove][2];
+        int angle    = bareAngle*(360/post.getObject().getBasicAngle());
+        int numRot   = Math.abs(bareAngle);
+
+        if( angle!=0 )
+          {
+          mCanRotate = false;
+          post.addRotation(this, axis, rowBitmap, -angle, numRot*DURATION_MILLIS);
+          }
+        else
+          {
+          android.util.Log.e("solution", "error: solution contains angle 0");
+          }
+        }
+      }
+    else
+      {
+      android.util.Log.e("solution", "failed to back move!");
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void setupMoves(final RubikActivity act, int numMoves, String moves)
+    {
+    android.util.Log.e("solution", "got "+numMoves+" moves: "+moves);
+
+    mCanRotate= true;
+    mCurrMove = 0;
+    mNumMoves = numMoves;
+    mMoves    = new int[mNumMoves][3];
+
+    RubikPattern.parseMoves(mMoves,numMoves,moves);
+
+    mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
@@ -177,4 +280,11 @@ public class RubikStateSolution extends RubikStateAbstract
     {
 
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onActionFinished(final long effectID)
+    {
+    mCanRotate = true;
+    }
   }
diff --git a/src/main/java/org/distorted/states/RubikStateSolver.java b/src/main/java/org/distorted/states/RubikStateSolver.java
index 1b904eb5..65da6e37 100644
--- a/src/main/java/org/distorted/states/RubikStateSolver.java
+++ b/src/main/java/org/distorted/states/RubikStateSolver.java
@@ -134,8 +134,7 @@ public class RubikStateSolver extends RubikStateAbstract
 
   void leaveState(RubikActivity act)
     {
-    RubikPostRender post = act.getPostRender();
-    post.resetAllTextureMaps();
+
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -177,11 +176,19 @@ public class RubikStateSolver extends RubikStateAbstract
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
-  private void setSolved( RubikActivity act, int numMoves, String moves)
+  private void setSolved( final RubikActivity act, final int numMoves, final String moves)
     {
-    RubikState.switchState(act,RubikState.SOLU);
+    act.runOnUiThread(new Runnable()
+      {
+      @Override
+      public void run()
+        {
+        RubikState.switchState(act,RubikState.SOLU);
+        RubikStateSolution solution = (RubikStateSolution) RubikState.SOLU.getStateClass();
+        solution.setupMoves(act, numMoves, moves);
+        }
+      });
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -261,7 +268,7 @@ public class RubikStateSolver extends RubikStateAbstract
         {
         if( !mSolving )
           {
-          String cubeString = "INVALID"; // TODO: obtain a valid cube string
+          String cubeString = retCubeString();
           Solver solver = new Solver(cubeString, act );
           solver.start();
           mSolving = true;
@@ -286,6 +293,8 @@ public class RubikStateSolver extends RubikStateAbstract
       @Override
       public void onClick(View v)
         {
+        RubikPostRender post = act.getPostRender();
+        post.resetAllTextureMaps();
         RubikState.goBack(act);
         }
       });
@@ -310,6 +319,38 @@ public class RubikStateSolver extends RubikStateAbstract
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+	private String retCubeString()
+    {
+		String ret="UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB";
+/*
+		int color;
+		int F=retColor(FRONT , 1,1);
+		int B=retColor(BACK  , 1,1);
+		int L=retColor(LEFT  , 1,1);
+		int R=retColor(RIGHT , 1,1);
+		int U=retColor(TOP   , 1,1);
+		int D=retColor(BOTTOM, 1,1);
+
+		for(int face in {TOP,RIGHT,FRONT,BOTTOM,LEFT,BACK} )
+		  for(int row=0; row<mSize; row++)
+			  for(int col=0; col<mSize; col++)
+			    {
+				  color = retColor(TOP,col,row);
+
+				  if(color==F) ret+="F";
+				  if(color==B) ret+="B";
+				  if(color==L) ret+="L";
+				  if(color==R) ret+="R";
+				  if(color==U) ret+="U";
+				  if(color==D) ret+="D";
+			    }
+*/
+		return ret;
+	  }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
