commit 2ef489e234d57175818a6bdae15d0b360981b6bf
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Mar 29 13:32:12 2021 +0200

    Progress making the Diamond class support any size.

diff --git a/src/main/java/org/distorted/objects/TwistyCube.java b/src/main/java/org/distorted/objects/TwistyCube.java
index 625dca38..74f8e90d 100644
--- a/src/main/java/org/distorted/objects/TwistyCube.java
+++ b/src/main/java/org/distorted/objects/TwistyCube.java
@@ -213,7 +213,7 @@ class TwistyCube extends TwistyObject
 
   int getFaceColor(int cubit, int cubitface, int size)
     {
-    return CUBITS[cubit].mRotationRow[cubitface/2] == (cubitface%2==0 ? 1<<(size-1):1) ? cubitface : NUM_FACES;
+    return CUBITS[cubit].mRotationRow[cubitface/2] == (cubitface%2==0 ? (1<<(size-1)):1) ? cubitface : NUM_FACES;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistyDiamond.java b/src/main/java/org/distorted/objects/TwistyDiamond.java
index 1edf9dee..f0a69086 100644
--- a/src/main/java/org/distorted/objects/TwistyDiamond.java
+++ b/src/main/java/org/distorted/objects/TwistyDiamond.java
@@ -52,10 +52,10 @@ public class TwistyDiamond extends TwistyObject
 
   private static final int[] FACE_COLORS = new int[]
          {
-           COLOR_GREY  , COLOR_VIOLET,
-           COLOR_YELLOW, COLOR_WHITE ,
-           COLOR_BLUE  , COLOR_RED   ,
-           COLOR_ORANGE, COLOR_GREEN
+           COLOR_ORANGE, COLOR_VIOLET,
+           COLOR_WHITE , COLOR_BLUE  ,
+           COLOR_YELLOW, COLOR_RED   ,
+           COLOR_GREEN , COLOR_GREY
          };
 
   // All legal rotation quats of a Diamond: unit + three 180 deg turns + 8 generators
@@ -78,19 +78,18 @@ public class TwistyDiamond extends TwistyObject
 
   private static final float DIST = 0.50f;
 
-  // Colors of the faces of cubits. Each cubit has 8 faces
-  private static final int[][] mOctaFaceMap = new int[][]
+  private static final int[][] mFaceNeutralQuatIndex = new int[][]
          {
-           { 6,1,8,8, 2,5,8,8 },
-           { 8,1,3,8, 8,5,7,8 },
-           { 8,8,3,4, 8,8,7,0 },
-           { 6,8,8,4, 2,8,8,0 },
-           { 6,1,3,4, 8,8,8,8 },
-           { 8,8,8,8, 2,5,7,0 },
+             {6,10},
+             {4, 8},
+             {7,11},
+             {5, 9},
+             {7,11},
+             {5, 9},
+             {6,10},
+             {4, 8}
          };
 
-  private static final int[] mTetraFaceMap = new int[] { 1, 3, 4, 6, 5, 7, 0, 2 };
-
   private static MeshBase mOctaMesh, mTetraMesh;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -313,14 +312,14 @@ public class TwistyDiamond extends TwistyObject
     {
     switch(tetra)
       {
-      case 0 : return 0;
-      case 1 : return 1;
-      case 2 : return 2;
-      case 3 : return 3;
-      case 4 : return 4;
-      case 5 : return 5;
-      case 6 : return 6;
-      case 7 : return 7;
+      case 0 : return 1;
+      case 1 : return 2;
+      case 2 : return 3;
+      case 3 : return 0;
+      case 4 : return 5;
+      case 5 : return 6;
+      case 6 : return 7;
+      case 7 : return 4;
       default: return 8;
       }
     }
@@ -333,14 +332,14 @@ public class TwistyDiamond extends TwistyObject
 
     switch( retFaceTetraBelongsTo(cubit-numO, numLayers) )
       {
-      case 0: return new Static4D(0,-SQ2/2,0,SQ2/2);    //  90 along Y
-      case 1: return QUATS[1];                          // 180 along Y
-      case 2: return new Static4D(0,+SQ2/2,0,SQ2/2);    //  90 along Y
-      case 3: return QUATS[0];                          // unit quat
-      case 4: return new Static4D(SQ2/2, 0,SQ2/2,0);    //
-      case 5: return new Static4D(     1,0,0,    0);    // 180 along X
-      case 6: return new Static4D(-SQ2/2,0,SQ2/2,0);    //
-      case 7: return new Static4D(0,     0,1,    0);    // 180 along Z
+      case 0: return QUATS[0];                          // unit quat
+      case 1: return new Static4D(0,-SQ2/2,0,SQ2/2);    //  90 along Y
+      case 2: return QUATS[1];                          // 180 along Y
+      case 3: return new Static4D(0,+SQ2/2,0,SQ2/2);    //  90 along
+      case 4: return new Static4D(0,     0,1,    0);    // 180 along Z
+      case 5: return new Static4D(SQ2/2, 0,SQ2/2,0);    //
+      case 6: return new Static4D(     1,0,0,    0);    // 180 along X
+      case 7: return new Static4D(-SQ2/2,0,SQ2/2,0);    //
       }
 
     return null;
@@ -372,19 +371,33 @@ public class TwistyDiamond extends TwistyObject
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
-  int getFaceColor(int cubit, int cubitface, int numLayers)
+  int getFaceColor(int cubit, int cubitface, int size)
     {
-    int numO = getNumOctahedrons(numLayers);
+    int numO = getNumOctahedrons(size);
 
     if( cubit<numO )
       {
-      return mOctaFaceMap[cubit][cubitface];
+      int axis = 0;
+      int layer= 1;
+
+      switch(cubitface)
+        {
+        case 0: axis = 2; layer =             1; break;
+        case 1: axis = 0; layer = (1<<(size-1)); break;
+        case 2: axis = 3; layer =             1; break;
+        case 3: axis = 1; layer = (1<<(size-1)); break;
+        case 4: axis = 3; layer = (1<<(size-1)); break;
+        case 5: axis = 1; layer =             1; break;
+        case 6: axis = 2; layer = (1<<(size-1)); break;
+        case 7: axis = 0; layer =             1; break;
+        }
+
+      return CUBITS[cubit].mRotationRow[axis] == layer ? cubitface : NUM_FACES;
       }
     else
       {
-      return cubitface>0 ? 8 : mTetraFaceMap[retFaceTetraBelongsTo(cubit-numO, numLayers)];
+      return cubitface>0 ? NUM_FACES : retFaceTetraBelongsTo(cubit-numO, size);
       }
     }
 
@@ -508,57 +521,39 @@ public class TwistyDiamond extends TwistyObject
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// The Diamond is solved if and only if:
+// The (2 and 3-layered) Diamond is solved if and only if:
 //
-// 1) all 6 octahedrons are rotated with the same quat
-// 2) the 8 tetrahedrons are rotated with the quat and, optionally, the can also be rotated
-//    by multitudes of 120 degrees along the face they are the center of.
+// 1) all octahedrons are rotated with the same quat
+// 2) all tetrahedrons might be also optionally rotated by a 'face neutral' pair of quats
+//    (indexes of those are kept in the 'mFaceNeutralQuattIndex' table)
 //
-// so:
-// 1) cubits 6,12: can also be QUAT 6,10
-// 2) cubits 7,13: can also be QUAT 4,8
-// 3) cubits 8,10: can also be QUAT 7,11
-// 4) cubits 9,11: can also be QUAT 5,9
-// TODO
+// Note: this doesn't work for numLayers > 3, because then we have some 'internal' octahedrons,
+// which also might be rotate by 'face neutral' pair of quats. We don't care about this (yet?)
 
   public boolean isSolved()
     {
     int q = CUBITS[0].mQuatIndex;
+    int layers = getNumLayers();
+    int numO = getNumOctahedrons(layers);
 
-    if ( CUBITS[ 1].mQuatIndex == q &&
-         CUBITS[ 2].mQuatIndex == q &&
-         CUBITS[ 3].mQuatIndex == q &&
-         CUBITS[ 4].mQuatIndex == q &&
-         CUBITS[ 5].mQuatIndex == q  )
+    for(int i=1; i<numO; i++)
       {
-      int q1 = mulQuat(q,5);
-      int q2 = mulQuat(q,9);
-
-      if( CUBITS[ 9].mQuatIndex != q && CUBITS[ 9].mQuatIndex != q1 && CUBITS[ 9].mQuatIndex != q2 ) return false;
-      if( CUBITS[11].mQuatIndex != q && CUBITS[11].mQuatIndex != q1 && CUBITS[11].mQuatIndex != q2 ) return false;
-
-      q1 = mulQuat(q,4);
-      q2 = mulQuat(q,8);
-
-      if( CUBITS[ 7].mQuatIndex != q && CUBITS[ 7].mQuatIndex != q1 && CUBITS[ 7].mQuatIndex != q2 ) return false;
-      if( CUBITS[13].mQuatIndex != q && CUBITS[13].mQuatIndex != q1 && CUBITS[13].mQuatIndex != q2 ) return false;
-
-      q1 = mulQuat(q,6);
-      q2 = mulQuat(q,10);
-
-      if( CUBITS[ 6].mQuatIndex != q && CUBITS[ 6].mQuatIndex != q1 && CUBITS[ 6].mQuatIndex != q2 ) return false;
-      if( CUBITS[12].mQuatIndex != q && CUBITS[12].mQuatIndex != q1 && CUBITS[12].mQuatIndex != q2 ) return false;
+      if( CUBITS[i].mQuatIndex != q ) return false;
+      }
 
-      q1 = mulQuat(q,7);
-      q2 = mulQuat(q,11);
+    int qI, q1Index, q2Index, face;
 
-      if( CUBITS[ 8].mQuatIndex != q && CUBITS[ 8].mQuatIndex != q1 && CUBITS[ 8].mQuatIndex != q2 ) return false;
-      if( CUBITS[10].mQuatIndex != q && CUBITS[10].mQuatIndex != q1 && CUBITS[10].mQuatIndex != q2 ) return false;
+    for(int i=numO; i<NUM_CUBITS; i++)
+      {
+      face    = retFaceTetraBelongsTo(i-numO,layers);
+      q1Index = mFaceNeutralQuatIndex[face][0];
+      q2Index = mFaceNeutralQuatIndex[face][1];
+      qI      = CUBITS[i].mQuatIndex;
 
-      return true;
+      if(  qI != q && qI != mulQuat(q,q1Index) && qI != mulQuat(q,q2Index) ) return false;
       }
 
-    return false;
+    return true;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -573,20 +568,38 @@ public class TwistyDiamond extends TwistyObject
 
   public int getObjectName(int numLayers)
     {
-    return R.string.diam2;
+    switch(numLayers)
+      {
+      case 2: return R.string.diam2;
+      case 3: return R.string.diam3;
+      }
+
+    return 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getInventor(int numLayers)
     {
-    return R.string.diam2_inventor;
+    switch(numLayers)
+      {
+      case 2: return R.string.diam2_inventor;
+      case 3: return R.string.diam3_inventor;
+      }
+
+    return 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int numLayers)
     {
-    return 5;
+    switch(numLayers)
+      {
+      case 2: return 5;
+      case 3: return 7;
+      }
+
+    return 0;
     }
 }
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index eece07cb..c16048b8 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -82,6 +82,7 @@
     <string name="skew2" translatable="false">Skewb</string>
     <string name="skew3" translatable="false">Master Skewb</string>
     <string name="diam2" translatable="false">Skewb Diamond</string>
+    <string name="diam3" translatable="false">Face Turning Octahedron</string>
     <string name="redi2" translatable="false">Redi Cube</string>
     <string name="heli3" translatable="false">Helicopter Cube</string>
     <string name="ivy2"  translatable="false">Ivy Cube</string>
@@ -107,6 +108,7 @@
     <string name="skew2_inventor" translatable="false">Tony Durham, 1982</string>
     <string name="skew3_inventor" translatable="false">Katsuhiko Okamoto, 2003</string>
     <string name="diam2_inventor" translatable="false">Uwe Meffert, 1984</string>
+    <string name="diam3_inventor" translatable="false">David Pitcher, 2003</string>
     <string name="redi2_inventor" translatable="false">Oskar van Deventer, 2009</string>
     <string name="heli3_inventor" translatable="false">Adam G. Cowan, 2006</string>
     <string name="ivy2_inventor"  translatable="false">Eitan Cher, 2009</string>
