commit 3a2dfb4a7deb4b1e10311def218a7b8c44d13527
Author: leszek <leszek@koltunski.pl>
Date:   Sat Jan 4 17:08:41 2025 +0100

    New verifier mechanism finished and being used by both KILO3 and CUBE3 algorithmic solvers.

diff --git a/src/main/java/org/distorted/objectlib/main/TwistyObjectWithStickers.java b/src/main/java/org/distorted/objectlib/main/TwistyObjectWithStickers.java
index 4885394e..b23f3882 100644
--- a/src/main/java/org/distorted/objectlib/main/TwistyObjectWithStickers.java
+++ b/src/main/java/org/distorted/objectlib/main/TwistyObjectWithStickers.java
@@ -53,7 +53,9 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
   // needed for verifiers
   private float[][][] mFaceCenters;     // fc[cubit][face] = point in the face, its center.
   private int[][] mCurrStickers;        // cs[cubit][face] = index of the sticker the face is stickered with at the moment
-  private int[][] mOrigStickers;        // os[cubit][face] = original sticker index, before the user changed it by touching
+  private int[][] mOrigColors;          // oc[cubit][face] = original color of the sticker, before the user changed it by touching
+                                        // This is not the same as the 'sticker index' in mCurrStickers - only the same if there
+                                        // is only a single type of sticker!
   private int[][][] mCubitFaceQuatMap;  // cfq[cubit][face][quat] = if we take the face and rotate it with quat, which cubit
                                         // face does it become? Format: (targetCubit<<8) + targetFace.
   private int[] mOrbits;                // o[cubit] - the number of orbit the cubit belongs to (starting from 0)
@@ -621,6 +623,9 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
 
   private int getCubitAndFace(float[] point)
     {
+    int minCubit=0, minFace=0;
+    float minError = Float.MAX_VALUE;
+
     for(int c=0; c<mNumCubits; c++)
       {
       int numFaces = mFaceCenters[c].length;
@@ -631,12 +636,18 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
         float dx = point[0] - cent[0];
         float dy = point[1] - cent[1];
         float dz = point[2] - cent[2];
+        float error = dx*dx + dy*dy + dz*dz;
 
-        if( dx*dx + dy*dy + dz*dz < 0.01f ) return (c<<8)+f;
+        if( error<minError )
+          {
+          minCubit = c;
+          minFace = f;
+          minError = error;
+          }
         }
       }
 
-    return -1;
+    return (minCubit<<8) + minFace;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -647,9 +658,9 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
 
     for(int f=0; f<numFaces; f++)
       {
-      int orig = mOrigStickers[cubit][f];
+      int color = mOrigColors[cubit][f];
 
-      if( orig>=0 )
+      if( color>=0 )
         {
         int cubitFace = mCubitFaceQuatMap[cubit][f][quaternion];
 
@@ -657,7 +668,8 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
           {
           targetCubit = cubitFace>>8;
           int targetFace = cubitFace&0xff;
-          if( mCurrStickers[targetCubit][targetFace] != orig ) return -1;
+          int stickerColor = mCurrStickers[targetCubit][targetFace]%mNumFaceColors;
+          if( stickerColor != color ) return -1;
           }
         else return -1;
         }
@@ -693,8 +705,8 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
     int numFaces = shape.getNumFaces();
     Static4D cubitQuat = getCubitOrigQuat(cubit);
 
-    mFaceCenters[cubit] = new float[numFaces][];
-    mOrigStickers[cubit] = new int[numFaces];
+    mFaceCenters[cubit]  = new float[numFaces][];
+    mOrigColors[cubit]   = new int[numFaces];
     mCurrStickers[cubit] = new int[numFaces];
 
     float[] po = mCubitPos[cubit];
@@ -713,7 +725,7 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
 
     for(int f=0; f<numFaces; f++)
       {
-      mOrigStickers[cubit][f] = getOriginalCubitFaceColor(cubit,f);
+      mOrigColors[cubit][f] = getOriginalCubitFaceColor(cubit,f);
 
       mFaceCenters[cubit][f] = new float[3];
       shape.getFacePoint(f,tmp);
@@ -756,20 +768,52 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
       int numFaces = mCurrStickers[c].length;
       for(int f=0; f<numFaces; f++) mCurrStickers[c][f] = getCubitFaceStickerIndex(c,f);
       }
+/*
+    String cur="";
+    for(int c=0; c<mNumCubits; c++)
+      {
+      int[] fc = mCurrStickers[c];
+      for( int ff : fc ) cur += (ff+" ");
+      cur += "\n";
+      }
+
+    android.util.Log.e("D", "curr stickers: \n"+cur);
+*/
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void prepareVerifierStuff()
     {
-    mFaceCenters = new float[mNumCubits][][];
-    mOrigStickers = new int[mNumCubits][];
+    mFaceCenters  = new float[mNumCubits][][];
+    mOrigColors   = new int[mNumCubits][];
     mCurrStickers = new int[mNumCubits][];
     mCubitFaceQuatMap = new int[mNumCubits][][];
     float[] tmp = new float[4];
 
     for(int c=0; c<mNumCubits; c++) computeCubitFaceCenterAndColor(c,tmp);
     for(int c=0; c<mNumCubits; c++) computeCubitFaceQuatMap(c,tmp);
+/*
+    String cen="";
+    for(int c=0; c<mNumCubits; c++)
+      {
+      float[][] fc = mFaceCenters[c];
+      for( float[] ff : fc ) cen += ("("+ff[0]+" "+ff[1]+" "+ff[2]+")");
+      cen += "\n";
+      }
+
+    android.util.Log.e("D", "centers: \n"+cen);
+
+    String ori="";
+    for(int c=0; c<mNumCubits; c++)
+      {
+      int[] fc = mOrigColors[c];
+      for( int ff : fc ) ori += (ff+" ");
+      ori += "\n";
+      }
+
+    android.util.Log.e("D", "orig colors: \n"+ori);
+*/
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -781,7 +825,7 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
     for( int c=0; c<mNumCubits; c++)
       if( mOrbits[c]==-1 )
         {
-        android.util.Log.e("D", "generating cubit of orbit "+neworb+" : "+c);
+        //android.util.Log.e("D", "generating cubit of orbit "+neworb+" : "+c);
         mOrbits[c] = neworb;
         ret++;
         genCubit = c;
@@ -793,20 +837,14 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
     for(int q=0; q<mNumQuats; q++)
       {
       int cubit = mCubitFaceQuatMap[genCubit][face][q]>>8;
-
-      if( cubit<0 )
-        {
-        android.util.Log.e("D", "error: genCubit="+genCubit+" face: "+face+" quat: "+q);
-        }
-
       if( mOrbits[cubit]==-1 ) ret++;
       else if( mOrbits[cubit]<neworb ) System.out.println("newOrbit: impossible!! cubit="+cubit+" neworb="+neworb);
       mOrbits[cubit] = neworb;
 
-      android.util.Log.e("D", "new cubit of orbit "+neworb+" : "+cubit);
+      //android.util.Log.e("D", "new cubit of orbit "+neworb+" : "+cubit);
       }
 
-    android.util.Log.e("D", "returning "+ret);
+    //android.util.Log.e("D", "returning "+ret);
     return ret;
     }
 
@@ -844,14 +882,14 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
 
     for(int c=0; c<mNumCubits; c++)
       {
-      int numFaces = mOrigStickers[c].length;
+      int numFaces = mOrigColors[c].length;
       mTwistInfo[c] = new int[numFaces];
       int index=0;
 
       for(int f=0; f<numFaces; f++)
         {
-        int s = mOrigStickers[c][f];
-        if( s>=0 ) mTwistInfo[c][index++] = f;
+        int clr = mOrigColors[c][f];
+        if( clr>=0 ) mTwistInfo[c][index++] = f;
         }
       for(int f=index; f<numFaces; f++) mTwistInfo[c][f] = -1;
       }
@@ -864,19 +902,19 @@ public abstract class TwistyObjectWithStickers extends TwistyObjectSolved
   public int[] getStickersOfMissingCubit(int cubit)
     {
     if( mFaceCenters==null ) prepareVerifierStuff();
-    int[] stickers = mOrigStickers[cubit];
+    int[] colors = mOrigColors[cubit];
     int numOuter = 0;
 
-    for( int s : stickers )
-      if( s>=0 ) numOuter++;
+    for( int clr : colors )
+      if( clr>=0 ) numOuter++;
 
     if( numOuter>0 )
       {
       int[] ret = new int[numOuter];
       int index = 0;
 
-      for( int s : stickers )
-        if( s>=0 ) ret[index++] = s;
+      for( int clr : colors )
+        if( clr>=0 ) ret[index++] = clr;
 
       return ret;
       }
diff --git a/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicCUBE3.java b/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicCUBE3.java
index b9c3bb37..70439946 100644
--- a/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicCUBE3.java
+++ b/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicCUBE3.java
@@ -18,247 +18,56 @@ import org.distorted.objectlib.solvers.tablebases.TablebaseHelpers;
 
 public class SolverAlgorithmicCUBE3 extends SolverAlgorithmic
 {
-  protected int mErrColor1, mErrColor2, mErrColor3;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   public SolverAlgorithmicCUBE3(OperatingSystemInterface os, TwistyObject object)
     {
     mSolver = new PhasedSolver3x3Beginner();
     mSolvedObject = mSolver.getObject();
-    mFaceColors = new int[6];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void fillCornerTwists(int[] output, int[][] corners, int[] perm)
-    {
-    for(int i=0; i<8; i++)
-      {
-      int[] c = corners[perm[i]];
-
-           if( c[0]==mFaceColors[0] || c[0]==mFaceColors[1] ) output[i] = 0;
-      else if( c[1]==mFaceColors[0] || c[1]==mFaceColors[1] ) output[i] = 1;
-      else                                                    output[i] = 2;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private int cornerIndex(int[][] corners, int[] ind)
-    {
-    int c1 = mFaceColors[ind[0]];
-    int c2 = mFaceColors[ind[1]];
-    int c3 = mFaceColors[ind[2]];
-
-    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)
-    {
-    int[][] ind = new int[][] { {1,3,5},{1,4,3},{1,5,2},{1,2,4},{0,5,3},{0,3,4},{0,2,5},{0,4,2} };
-
-    for(int i=0; i<8; i++) output[i] = cornerIndex(corners,ind[i]);
-
-    for(int i=0; i<8; i++)
-      if( output[i]==-1 )
-        {
-        mErrColor1 = ind[i][0];
-        mErrColor2 = ind[i][1];
-        mErrColor3 = ind[i][2];
-        return ERROR_HEX_CORNER_MISSING;
-        }
-
-    return 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void getCorners(TwistyObject object, int[][] corners)
-    {
-    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);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void getEdges(TwistyObject object, int[][] edges)
-    {
-    edges[ 0][0] = object.getCubitFaceStickerIndex( 8,5);
-    edges[ 0][1] = object.getCubitFaceStickerIndex( 8,3);
-
-    edges[ 1][0] = object.getCubitFaceStickerIndex( 9,3);
-    edges[ 1][1] = object.getCubitFaceStickerIndex( 9,5);
-
-    edges[ 2][0] = object.getCubitFaceStickerIndex(10,3);
-    edges[ 2][1] = object.getCubitFaceStickerIndex(10,5);
-
-    edges[ 3][0] = object.getCubitFaceStickerIndex(11,5);
-    edges[ 3][1] = object.getCubitFaceStickerIndex(11,3);
-
-    edges[ 4][0] = object.getCubitFaceStickerIndex(12,3);
-    edges[ 4][1] = object.getCubitFaceStickerIndex(12,5);
-
-    edges[ 5][0] = object.getCubitFaceStickerIndex(13,5);
-    edges[ 5][1] = object.getCubitFaceStickerIndex(13,3);
-
-    edges[ 6][0] = object.getCubitFaceStickerIndex(14,3);
-    edges[ 6][1] = object.getCubitFaceStickerIndex(14,5);
-
-    edges[ 7][0] = object.getCubitFaceStickerIndex(15,5);
-    edges[ 7][1] = object.getCubitFaceStickerIndex(15,3);
-
-    edges[ 8][0] = object.getCubitFaceStickerIndex(16,5);
-    edges[ 8][1] = object.getCubitFaceStickerIndex(16,3);
-
-    edges[ 9][0] = object.getCubitFaceStickerIndex(17,3);
-    edges[ 9][1] = object.getCubitFaceStickerIndex(17,5);
-
-    edges[10][0] = object.getCubitFaceStickerIndex(18,5);
-    edges[10][1] = object.getCubitFaceStickerIndex(18,3);
-
-    edges[11][0] = object.getCubitFaceStickerIndex(19,3);
-    edges[11][1] = object.getCubitFaceStickerIndex(19,5);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private int edgeIndex(int[][] edges, int[] ind)
+  public int[] validatePosition(TwistyObject object)
     {
-    int c1 = mFaceColors[ind[0]];
-    int c2 = mFaceColors[ind[1]];
+    int[] quats = object.computeCubitQuats();
+    int numQ = quats.length;
 
-    for(int i=0; i<12; i++)
+    for(int q=0; q<numQ; q++)
       {
-      int[] e = edges[i];
-      if( (e[0]==c1 && e[1]==c2) || (e[0]==c2 && e[1]==c1) ) return i;
-      }
-
-    return -1;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private int retEdgePermutation(int[] output, int[][] edges)
-    {
-    int[][] ind = new int[][] { {5,3},{4,3},{5,2},{4,2},{5,1},{4,1},{5,0},{4,0},{3,1},{2,1},{3,0},{2,0} };
-
-    for(int i=0; i<12; i++) output[i] = edgeIndex(edges,ind[i]);
-
-    for(int i=0; i<12; i++)
-      if( output[i]==-1 )
+      if( quats[q]<0 )
         {
-        mErrColor1 = ind[i][0];
-        mErrColor2 = ind[i][1];
-        return ERROR_HEX_EDGE_MISSING;
+        int[] st = object.getStickersOfMissingCubit(q);
+
+        switch(st.length)
+          {
+          case 1: return new int[] {ERROR_HEX_CENTER_MISSING, st[0]};
+          case 2: return new int[] {ERROR_HEX_EDGE_MISSING  , st[0],st[1]};
+          case 3: return new int[] {ERROR_HEX_CORNER_MISSING, st[0],st[1],st[2]};
+          default:System.out.println("Error in validatePosition: st length = "+st.length);
+          }
+        break;
         }
-
-    return 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void fillEdgeTwists(int[] output, int[][] edges, int[] perm)
-    {
-    for(int i=0; i<12; i++)
-      {
-      int[] e = edges[perm[i]];
-      output[i] = e[0]>e[1] ? 0 : 1;
       }
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    int[][] perms = object.getPermutations(quats);
+    boolean evenC = TablebaseHelpers.permutationIsEven(perms[0]);
+    boolean evenE = TablebaseHelpers.permutationIsEven(perms[1]);
 
-  private void computeFaceColors(TwistyObject object)
-    {
-    for(int i=0; i<6; i++) mFaceColors[i] = object.getCubitFaceStickerIndex(20+i,4);
-    }
+    if( evenC!=evenE ) return new int[] {ERROR_TWO_CORNERS_TWO_EDGES};
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public int[] validatePosition(TwistyObject object)
-    {
-    computeFaceColors(object);
-
-    int[][] corners= new int[8][3];
-    getCorners(object,corners);
-
-    //for(int i=0; i<8; i++) android.util.Log.e("D", "corner: "+i+" : "+corners[i][0]+" "+corners[i][1]+" "+corners[i][2]);
-    //for(int i=0; i<6; i++) android.util.Log.e("D", "face color: "+i+" : "+mFaceColors[i]);
-
-    int[] permC = new int[8];
-    int result0 = retCornerPermutation(permC,corners);
-    if( result0<0 ) return new int[] {result0,mErrColor1,mErrColor2,mErrColor3};
-
-    int[] twistC = new int[8];
-    fillCornerTwists(twistC,corners,permC);
+    int[][] twists = object.getTwists(quats);
 
     int totalTwistC = 0;
-    for(int i=0; i<8; i++) totalTwistC += twistC[i];
-    if( ((totalTwistC)%3) != 0 ) return new int[] {ERROR_CORNER_TWISTED};
-
-    int[][] edges = new int[12][2];
-    getEdges(object,edges);
-
-    //for(int i=0; i<12; i++) android.util.Log.e("D", "edge: "+i+" : "+edges[i][0]+" "+edges[i][1]);
-
-    int[] permE = new int[12];
-    int result1 = retEdgePermutation(permE,edges);
-    if( result1<0 ) return new int[] {result1,mErrColor1,mErrColor2,mErrColor3};
-
-    int[] twistE = new int[12];
-    fillEdgeTwists(twistE,edges,permE);
+    int[] twistC = twists[0];
+    for( int t : twistC ) totalTwistC += t;
 
     int totalTwistE = 0;
-    for(int i=0; i<12; i++) totalTwistE += twistE[i];
-    if( ((totalTwistE)%2) != 0 ) return new int[] {ERROR_EDGE_TWISTED};
-
-    boolean evenC = TablebaseHelpers.permutationIsEven(permC);
-    boolean evenE = TablebaseHelpers.permutationIsEven(permE);
+    int[] twistE = twists[1];
+    for( int t : twistE ) totalTwistE += t;
 
-    if( evenC^evenE ) return new int[] {ERROR_TWO_CORNERS_TWO_EDGES};
+    if( (totalTwistC%3) !=0 ) return new int[] {ERROR_CORNER_TWISTED};
+    if( (totalTwistE%2) !=0 ) return new int[] {ERROR_EDGE_TWISTED};
 
-    return object.computeCubitQuats();
+    return quats;
     }
 }  
 
diff --git a/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicKILO3.java b/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicKILO3.java
index 844344e4..571fe321 100644
--- a/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicKILO3.java
+++ b/src/main/java/org/distorted/objectlib/solvers/verifiers/SolverAlgorithmicKILO3.java
@@ -40,46 +40,11 @@ public class SolverAlgorithmicKILO3 extends SolverAlgorithmic
         }
 
     int[][] perms = object.getPermutations(quats);
-/*
-    for(int o=0; o<perms.length; o++)
-      {
-      String s="";
-      int len = perms[o].length;
-
-      for(int e=0; e<len; e++)
-        {
-        s += " ";
-        s += perms[o][e];
-        }
-
-      android.util.Log.e("D", "permutation "+o+" : "+s);
-      }
-*/
-    if( !TablebaseHelpers.permutationIsEven(perms[0]) )
-      {
-      return new int[] {ERROR_TWO_CORNERS};
-      }
+    if( !TablebaseHelpers.permutationIsEven(perms[0]) ) return new int[] {ERROR_TWO_CORNERS};
 
     int[][] twists = object.getTwists(quats);
-/*
-    for(int o=0; o<twists.length; o++)
-      {
-      String s="";
-      int len = twists[o].length;
-
-      for(int e=0; e<len; e++)
-        {
-        s += " ";
-        s += twists[o][e];
-        }
-
-      android.util.Log.e("D", "twists of orbit "+o+" : "+s);
-      }
-*/
     int totalTwist = 0;
-    int[] twist = twists[0];
-    for( int t : twist ) totalTwist += t;
-
+    for( int t : twists[0] ) totalTwist += t;
     if( (totalTwist%3)!=0 ) return new int[] {ERROR_CORNER_TWISTED};
 
     return quats;
