commit a4569df4dda7fea5fab757e4c40036665662e84b
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sun Mar 12 01:41:35 2023 +0100

    Beginnings of the 2x2 solver.

diff --git a/src/main/java/org/distorted/solvers/SolverCube2.java b/src/main/java/org/distorted/solvers/SolverCube2.java
new file mode 100644
index 00000000..706a7cfa
--- /dev/null
+++ b/src/main/java/org/distorted/solvers/SolverCube2.java
@@ -0,0 +1,312 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2023 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.solvers;
+
+import android.content.res.Resources;
+
+import org.distorted.main.R;
+import org.distorted.objectlib.main.ObjectSignatures;
+import org.distorted.objectlib.main.TwistyObject;
+import org.distorted.objectlib.tablebases.ImplementedTablebasesList;
+import org.distorted.objectlib.tablebases.TablebaseHelpers;
+import org.distorted.objectlib.tablebases.TablebasesAbstract;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class SolverCube2 extends SolverTablebase
+{
+  private static final int ERROR_CORNER_135_MISSING = -1;
+  private static final int ERROR_CORNER_134_MISSING = -2;
+  private static final int ERROR_CORNER_125_MISSING = -3;
+  private static final int ERROR_CORNER_124_MISSING = -4;
+  private static final int ERROR_CORNER_035_MISSING = -5;
+  private static final int ERROR_CORNER_034_MISSING = -6;
+  private static final int ERROR_CORNER_025_MISSING = -7;
+  private static final int ERROR_CORNER_024_MISSING = -8;
+  private static final int ERROR_CORNERS_CANNOT     = -9;
+  private static final int ERROR_CORNER_TWISTED     = -10;
+
+  TablebasesAbstract mSolver;
+  private final int[] mFaceColors;
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+  private void fillCornerTwists(int[] output, int[][] corners, int[] perm)
+    {
+    // TODO
+    }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+  private int cornerIndex(int[][] corners, int i1, int i2, int i3)
+    {
+    int c1 = mFaceColors[i1];
+    int c2 = mFaceColors[i2];
+    int c3 = mFaceColors[i3];
+
+    for(int i=0; i<8; i++)
+      {
+      int[] cor = corners[i];
+
+      if( (cor[0]==c1 && cor[1]==c2 && cor[2]==c3) ||
+          (cor[0]==c2 && cor[1]==c3 && cor[2]==c1) ||
+          (cor[0]==c3 && cor[1]==c1 && cor[2]==c2)  ) return i;
+      }
+
+    return -1;
+    }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+  private int retCornerPermutation(int[] output, int[][] corners)
+    {
+    for(int i=0; i<8; i++) output[i] = -1;
+
+    output[0] = cornerIndex(corners, 1,2,5);
+    output[1] = cornerIndex(corners, 1,4,2);
+    output[2] = cornerIndex(corners, 1,5,3);
+    output[3] = cornerIndex(corners, 1,3,4);
+    output[4] = cornerIndex(corners, 0,5,2);
+    output[5] = cornerIndex(corners, 0,2,4);
+    output[6] = cornerIndex(corners, 0,3,5);
+    output[7] = cornerIndex(corners, 0,4,3);
+
+    if( output[0]==-1 ) { android.util.Log.e("D ", "135"); return ERROR_CORNER_135_MISSING; }
+    if( output[1]==-1 ) { android.util.Log.e("D ", "134"); return ERROR_CORNER_134_MISSING; }
+    if( output[2]==-1 ) { android.util.Log.e("D ", "125"); return ERROR_CORNER_125_MISSING; }
+    if( output[3]==-1 ) { android.util.Log.e("D ", "124"); return ERROR_CORNER_124_MISSING; }
+    if( output[4]==-1 ) { android.util.Log.e("D ", "035"); return ERROR_CORNER_035_MISSING; }
+    if( output[5]==-1 ) { android.util.Log.e("D ", "034"); return ERROR_CORNER_034_MISSING; }
+    if( output[6]==-1 ) { android.util.Log.e("D ", "025"); return ERROR_CORNER_025_MISSING; }
+    if( output[7]==-1 ) { android.util.Log.e("D ", "024"); return ERROR_CORNER_024_MISSING; }
+
+    return 0;
+    }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+  private int findColor(int[][] corners, int c1, int c2)
+    {
+    for(int i=0; i<8; i++)
+      {
+      int[] cor = corners[i];
+
+      if( cor[0]==c1 && cor[1]==c2 ) return cor[2];
+      if( cor[1]==c1 && cor[2]==c2 ) return cor[0];
+      if( cor[2]==c1 && cor[0]==c2 ) return cor[1];
+      }
+
+    return -1;
+    }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+  private int computeFaceColors(int[][] corners)
+    {
+    mFaceColors[1] = corners[1][0];
+    mFaceColors[2] = corners[1][2];
+    mFaceColors[4] = corners[1][1];
+
+    mFaceColors[0] = findColor(corners,mFaceColors[2],mFaceColors[4]);
+    mFaceColors[3] = findColor(corners,mFaceColors[4],mFaceColors[1]);
+    mFaceColors[5] = findColor(corners,mFaceColors[1],mFaceColors[2]);
+
+    for(int i=0; i<6; i++) android.util.Log.e("D", "face "+i+" : "+mFaceColors[i]);
+
+    for(int i=0; i<6; i++)
+      {
+      int color = mFaceColors[i];
+      if( color<0 ) return ERROR_CORNERS_CANNOT;
+
+      for(int j=i+1; j<6; j++)
+        if( mFaceColors[j]==color ) return ERROR_CORNERS_CANNOT;
+      }
+
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public SolverCube2(Resources res, TwistyObject object)
+    {
+    super(res,object);
+    mFaceColors = new int[6];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int tablebaseIndex(TwistyObject object)
+    {
+    int[][] corners= new int[8][3];
+
+    corners[0][0] = object.getCubitFaceStickerIndex(0,1);
+    corners[0][1] = object.getCubitFaceStickerIndex(0,3);
+    corners[0][2] = object.getCubitFaceStickerIndex(0,5);
+
+    corners[1][0] = object.getCubitFaceStickerIndex(1,3);
+    corners[1][1] = object.getCubitFaceStickerIndex(1,5);
+    corners[1][2] = object.getCubitFaceStickerIndex(1,1);
+
+    corners[2][0] = object.getCubitFaceStickerIndex(2,5);
+    corners[2][1] = object.getCubitFaceStickerIndex(2,1);
+    corners[2][2] = object.getCubitFaceStickerIndex(2,3);
+
+    corners[3][0] = object.getCubitFaceStickerIndex(3,1);
+    corners[3][1] = object.getCubitFaceStickerIndex(3,3);
+    corners[3][2] = object.getCubitFaceStickerIndex(3,5);
+
+    corners[4][0] = object.getCubitFaceStickerIndex(4,1);
+    corners[4][1] = object.getCubitFaceStickerIndex(4,3);
+    corners[4][2] = object.getCubitFaceStickerIndex(4,5);
+
+    corners[5][0] = object.getCubitFaceStickerIndex(5,1);
+    corners[5][1] = object.getCubitFaceStickerIndex(5,3);
+    corners[5][2] = object.getCubitFaceStickerIndex(5,5);
+
+    corners[6][0] = object.getCubitFaceStickerIndex(6,1);
+    corners[6][1] = object.getCubitFaceStickerIndex(6,3);
+    corners[6][2] = object.getCubitFaceStickerIndex(6,5);
+
+    corners[7][0] = object.getCubitFaceStickerIndex(7,1);
+    corners[7][1] = object.getCubitFaceStickerIndex(7,3);
+    corners[7][2] = object.getCubitFaceStickerIndex(7,5);
+/*
+    for(int i=0; i<8; i++)
+      for(int f=0; f<3; f++)
+        {
+        android.util.Log.e("D", "cubit "+i+" face "+f+" : "+corners[i][f]);
+        }
+*/
+    int result0 = computeFaceColors(corners);
+    if( result0<0 ) return result0;
+
+    int[] corner_perm = new int[8];
+    int result1 = retCornerPermutation(corner_perm,corners);
+    if( result1<0 ) return result1;
+
+    int[] perm = new int[7];
+
+    perm[0] = corner_perm[0]>1 ? corner_perm[0]-1 : corner_perm[0];
+    perm[1] = corner_perm[2]>1 ? corner_perm[2]-1 : corner_perm[2];
+    perm[2] = corner_perm[3]>1 ? corner_perm[3]-1 : corner_perm[3];
+    perm[3] = corner_perm[4]>1 ? corner_perm[4]-1 : corner_perm[4];
+    perm[4] = corner_perm[5]>1 ? corner_perm[5]-1 : corner_perm[5];
+    perm[5] = corner_perm[6]>1 ? corner_perm[6]-1 : corner_perm[6];
+    perm[6] = corner_perm[7]>1 ? corner_perm[7]-1 : corner_perm[7];
+
+    int perm_num = TablebaseHelpers.computePermutationNum(perm);
+/*
+    android.util.Log.e("D", "corner perm num="+perm_num);
+
+    for(int i=0; i<8; i++)
+      {
+      android.util.Log.e("D", "8perm "+i+" "+corner_perm[i]);
+      }
+    for(int i=0; i<7; i++)
+      {
+      android.util.Log.e("D", "7perm "+i+" "+perm[i]);
+      }
+*/
+    int[] twist = new int[8];
+    fillCornerTwists(twist,corners,corner_perm);
+
+    int totalTwist = 0;
+    for(int i=0; i<8; i++) totalTwist += twist[i];
+    if( ((totalTwist)%3) != 0 ) return ERROR_CORNER_TWISTED;
+
+    int twistNum = twist[0] + 3*(twist[2] + 3*(twist[3] + 3*(twist[4] + 3*(twist[5] + 3*twist[6]))));
+
+    return twistNum + 729*perm_num;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getColorIndex4(int face)
+    {
+    switch(mFaceColors[face])
+      {
+      case 0: return R.string.color_yellow4;
+      case 1: return R.string.color_white4;
+      case 2: return R.string.color_green4;
+      case 3: return R.string.color_blue4;
+      case 4: return R.string.color_red4;
+      case 5: return R.string.color_orange4;
+      }
+
+    return -1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getColorIndex3(int face)
+    {
+    switch(mFaceColors[face])
+      {
+      case 0: return R.string.color_yellow3;
+      case 1: return R.string.color_white3;
+      case 2: return R.string.color_green3;
+      case 3: return R.string.color_blue3;
+      case 4: return R.string.color_red3;
+      case 5: return R.string.color_orange3;
+      }
+
+    return -1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private String cornerError(Resources res, int face0, int face1, int face2)
+    {
+    int j0 = getColorIndex3(face0);
+    int j1 = getColorIndex3(face1);
+    int j2 = getColorIndex4(face2);
+
+    String c0 = res.getString(j0);
+    String c1 = res.getString(j1);
+    String c2 = res.getString(j2);
+
+    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String error(int index, Resources res)
+    {
+    switch(index)
+      {
+      case ERROR_CORNER_135_MISSING: return cornerError(res,1,3,5);
+      case ERROR_CORNER_134_MISSING: return cornerError(res,1,3,4);
+      case ERROR_CORNER_125_MISSING: return cornerError(res,1,2,5);
+      case ERROR_CORNER_124_MISSING: return cornerError(res,1,2,4);
+      case ERROR_CORNER_035_MISSING: return cornerError(res,0,3,5);
+      case ERROR_CORNER_034_MISSING: return cornerError(res,0,3,4);
+      case ERROR_CORNER_025_MISSING: return cornerError(res,0,2,5);
+      case ERROR_CORNER_024_MISSING: return cornerError(res,0,2,4);
+      case ERROR_CORNERS_CANNOT    : return res.getString(R.string.solver_generic_corners_cannot);
+      case ERROR_CORNER_TWISTED    : return res.getString(R.string.solver_generic_corner_twist);
+      }
+
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][] solution(int index, Resources res)
+    {
+    if( mSolver==null )
+      {
+      mSolver = ImplementedTablebasesList.createUnpacked(ObjectSignatures.CUBE_2);
+      if( mSolver!=null ) mSolver.createTablebase();
+      }
+
+    return mSolver!=null ? mSolver.solution(index,null) : null;
+    }
+}  
+
diff --git a/src/main/java/org/distorted/solvers/SolverCuboid232.java b/src/main/java/org/distorted/solvers/SolverCuboid232.java
index 0d4703f4..f3d3f41d 100644
--- a/src/main/java/org/distorted/solvers/SolverCuboid232.java
+++ b/src/main/java/org/distorted/solvers/SolverCuboid232.java
@@ -291,23 +291,7 @@ public class SolverCuboid232 extends SolverTablebase
 
     int corner_perm_num = TablebaseHelpers.computePermutationNum(corner_perm);
     int edge_perm_num = TablebaseHelpers.computePermutationNum(edge_perm2);
-/*
-    android.util.Log.e("D", "corner perm num="+corner_perm_num);
-    for(int i=0; i<8; i++)
-      {
-      android.util.Log.e("D", "corner perm "+i+" "+corner_perm[i]);
-      }
 
-    android.util.Log.e("D", "edge perm num="+edge_perm_num);
-    for(int i=0; i<4; i++)
-      {
-      android.util.Log.e("D", "edge perm "+i+" "+edge_perm[i]);
-      }
-    for(int i=0; i<3; i++)
-      {
-      android.util.Log.e("D", "edge perm2 "+i+" "+edge_perm2[i]);
-      }
-*/
     return edge_perm_num + 6*corner_perm_num;
     }
 
@@ -319,8 +303,8 @@ public class SolverCuboid232 extends SolverTablebase
       {
       case 0: return R.string.color_yellow4;
       case 1: return R.string.color_white4;
-      case 2: return R.string.color_blue4;
-      case 3: return R.string.color_green4;
+      case 2: return R.string.color_green4;
+      case 3: return R.string.color_blue4;
       case 4: return R.string.color_red4;
       case 5: return R.string.color_orange4;
       }
@@ -336,8 +320,8 @@ public class SolverCuboid232 extends SolverTablebase
       {
       case 0: return R.string.color_yellow3;
       case 1: return R.string.color_white3;
-      case 2: return R.string.color_blue3;
-      case 3: return R.string.color_green3;
+      case 2: return R.string.color_green3;
+      case 3: return R.string.color_blue3;
       case 4: return R.string.color_red3;
       case 5: return R.string.color_orange3;
       }
@@ -353,8 +337,8 @@ public class SolverCuboid232 extends SolverTablebase
       {
       case 0: return R.string.color_yellow6;
       case 1: return R.string.color_white6;
-      case 2: return R.string.color_blue6;
-      case 3: return R.string.color_green6;
+      case 2: return R.string.color_green6;
+      case 3: return R.string.color_blue6;
       case 4: return R.string.color_red6;
       case 5: return R.string.color_orange6;
       }
diff --git a/src/main/java/org/distorted/solvers/SolverMain.java b/src/main/java/org/distorted/solvers/SolverMain.java
index a09b0fbc..b369c316 100644
--- a/src/main/java/org/distorted/solvers/SolverMain.java
+++ b/src/main/java/org/distorted/solvers/SolverMain.java
@@ -101,6 +101,11 @@ public class SolverMain implements Runnable
       SolverTablebase solver = new SolverSkewbDiamond(mRes,mObject);
       solver.solve(screen);
       }
+    else if( mSignature==ObjectSignatures.CUBE_2 )
+      {
+      SolverTablebase solver = new SolverCube2(mRes,mObject);
+      solver.solve(screen);
+      }
     else
       {
       screen.displayErrorDialog(mRes.getString(R.string.solver_generic_not_implemented));
