Project

General

Profile

« Previous | Next » 

Revision a110ebe1

Added by Leszek Koltunski over 1 year ago

Pyraminx Duo solver: initial code which creates the unpacked DB (does not work still)

View differences:

src/main/java/org/distorted/objectlib/main/TwistyObjectCubit.java
252 252
    Static4D q = QuatHelper.quatMultiply(quat,mParent.mObjectQuats[mQuatIndex]);
253 253
    mQuatIndex = normalizeScrambleQuat(q);
254 254
    computeRotationRow();
255

  
256

  
257
    if( mCubitIndex==4 ) android.util.Log.e("D", "quat="+mQuatIndex);
258

  
259 255
    return mQuatIndex;
260 256
    }
261 257

  
src/main/java/org/distorted/objectlib/objects/TwistyPyraminxDuo.java
31 31

  
32 32
public class TwistyPyraminxDuo extends ShapeTetrahedron
33 33
{
34
  static final Static3D[] ROT_AXIS = new Static3D[]
34
  public static final Static3D[] ROT_AXIS = new Static3D[]
35 35
         {
36 36
           new Static3D(     0,-SQ3/3,-SQ6/3),
37 37
           new Static3D(     0,-SQ3/3, SQ6/3),
src/main/java/org/distorted/objectlib/tablebases/Tablebase.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.tablebases;
11

  
12
///////////////////////////////////////////////////////////////////////////////////////////////////
13

  
14
class Tablebase
15
{
16
  private final byte UNINITIALIZED = (byte)0xff;
17
  private final byte[] mUnpackedTable;
18
  private byte[] mPackedTable;
19

  
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

  
22
  Tablebase(int size)
23
    {
24
    mUnpackedTable = new byte[size];
25
    for(int i=0; i<size; i++) mUnpackedTable[i] = UNINITIALIZED;
26
    }
27

  
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29

  
30
  boolean insertUnpacked(int index, byte value)
31
    {
32
    if( mUnpackedTable[index]==UNINITIALIZED )
33
      {
34
      mUnpackedTable[index] = value;
35
      return true;
36
      }
37
    return false;
38
    }
39

  
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

  
42
  byte retrieveUnpacked(int index)
43
    {
44
    return mUnpackedTable[index];
45
    }
46

  
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

  
49
  private void createPacked(int size)
50
    {
51
    mPackedTable = new byte[(size+4)/5];
52
    }
53

  
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55

  
56
  private void insertPacked(int index, byte value)
57
    {
58
    int indexToInsert = index/5;
59
    byte actualInserted = (byte)(value%3);
60
    byte val = mPackedTable[indexToInsert];
61

  
62
    int b4 = val%3; val/=3;
63
    int b3 = val%3; val/=3;
64
    int b2 = val%3; val/=3;
65
    int b1 = val%3; val/=3;
66
    int b0 = val%3;
67

  
68
    switch(index%5)
69
      {
70
      case 0: b0 = actualInserted; break;
71
      case 1: b1 = actualInserted; break;
72
      case 2: b2 = actualInserted; break;
73
      case 3: b3 = actualInserted; break;
74
      case 4: b4 = actualInserted; break;
75
      }
76

  
77
    mPackedTable[indexToInsert] = (byte)(b4 + 3*(b3 + 3*(b2 + 3*(b1 + 3*b0))));
78
    }
79

  
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

  
82
  byte retrievePacked(int index)
83
    {
84
    int indexToRetrieve = index/5;
85
    byte val = mPackedTable[indexToRetrieve];
86

  
87
    byte b4 = (byte)(val%3); val/=3;
88
    byte b3 = (byte)(val%3); val/=3;
89
    byte b2 = (byte)(val%3); val/=3;
90
    byte b1 = (byte)(val%3); val/=3;
91
    byte b0 = (byte)(val%3);
92

  
93
    switch(index%5)
94
      {
95
      case 0: return b0;
96
      case 1: return b1;
97
      case 2: return b2;
98
      case 3: return b3;
99
      case 4: return b4;
100
      }
101

  
102
    return 0;
103
    }
104

  
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

  
107
  void pack()
108
    {
109
    int size = mUnpackedTable.length;
110
    createPacked(size);
111

  
112
    for(int i=0; i<size; i++)
113
      {
114
      byte unpacked = retrieveUnpacked(i);
115
      insertPacked(i,unpacked);
116
      }
117
    }
118
}
src/main/java/org/distorted/objectlib/tablebases/TablebasesCreator.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.tablebases;
11

  
12
import org.distorted.library.main.QuatHelper;
13
import org.distorted.library.type.Static3D;
14
import org.distorted.library.type.Static4D;
15
import org.distorted.objectlib.helpers.QuatGroupGenerator;
16

  
17
///////////////////////////////////////////////////////////////////////////////////////////////////
18

  
19
public abstract class TablebasesCreator
20
{
21
  private Tablebase mTablebase;
22
  private final Static3D[] mAxis;
23
  private final int mSize;
24
  private final int[][] mAngles;
25
  private final int mNumAxis;
26
  private final int[] mNumLayers;
27
  private final int mNumQuats;
28
  private final Static4D[] mQuats;
29
  private final int[][] mRotRow;
30
  private final int mNumCubits;
31
  private final float[][] mPosition;
32
  private final float[][] mCuts;
33
  private final int[] mNumCuts;
34
  private int[][] mQuatMult;
35

  
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

  
38
  abstract int getSize();
39
  abstract int[][] getBasicAngles();
40
  abstract Static3D[] getRotationAxis();
41
  abstract int[] getQuats(int index);
42
  abstract int getIndex(int[] quats);
43
  abstract float[][] getPosition();
44
  abstract float[][] getCuts();
45

  
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

  
48
  public TablebasesCreator()
49
    {
50
    mSize = getSize();
51
    mAngles = getBasicAngles();
52
    mAxis = getRotationAxis();
53
    mNumAxis = mAxis.length;
54
    mNumLayers = new int[mNumAxis];
55
    for(int i=0; i<mNumAxis; i++) mNumLayers[i] = mAngles[i].length;
56
    mQuats = QuatGroupGenerator.computeGroup(mAxis,mAngles);
57
    mNumQuats = mQuats.length;
58
    mPosition = getPosition();
59
    mNumCubits = mPosition.length;
60

  
61
    mCuts = getCuts();
62
    mNumCuts = new int[mNumAxis];
63

  
64
    for(int i=0; i<mNumAxis; i++)
65
      {
66
      mNumCuts[i] = (mCuts==null || mCuts[i]==null ? 0 : mCuts[i].length);
67
      }
68

  
69
    mRotRow = new int[mNumCubits][mNumAxis];
70

  
71
    for(int i=0; i<mNumCubits; i++)
72
      for(int j=0; j<mNumAxis; j++)
73
        {
74
        mRotRow[i][j] = computeRow(mPosition[i],j);
75
        }
76
    }
77

  
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

  
80
  private int computeRow(float[] pos, int axisIndex)
81
    {
82
    int ret=0;
83
    int len = pos.length/3;
84
    Static3D axis = mAxis[axisIndex];
85
    float axisX = axis.get0();
86
    float axisY = axis.get1();
87
    float axisZ = axis.get2();
88
    float casted, xoff=0, yoff=0, zoff=0;
89

  
90
    for(int i=0; i<len; i++)
91
      {
92
      casted = (pos[3*i]+xoff)*axisX + (pos[3*i+1]+yoff)*axisY + (pos[3*i+2]+zoff)*axisZ;
93
      ret |= computeSingleRow(axisIndex,casted);
94
      }
95

  
96
    return ret;
97
    }
98

  
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

  
101
  private int computeSingleRow(int axisIndex,float casted)
102
    {
103
    int num = mNumCuts[axisIndex];
104

  
105
    for(int i=0; i<num; i++)
106
      {
107
      if( casted<mCuts[axisIndex][i] ) return (1<<i);
108
      }
109

  
110
    return (1<<num);
111
    }
112

  
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
// remember about the double cover or unit quaternions!
115

  
116
  private int mulQuat(int q1, int q2)
117
    {
118
    Static4D result = QuatHelper.quatMultiply(mQuats[q1],mQuats[q2]);
119

  
120
    float rX = result.get0();
121
    float rY = result.get1();
122
    float rZ = result.get2();
123
    float rW = result.get3();
124

  
125
    final float MAX_ERROR = 0.1f;
126
    float dX,dY,dZ,dW;
127

  
128
    for(int i=0; i<mNumQuats; i++)
129
      {
130
      dX = mQuats[i].get0() - rX;
131
      dY = mQuats[i].get1() - rY;
132
      dZ = mQuats[i].get2() - rZ;
133
      dW = mQuats[i].get3() - rW;
134

  
135
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
136
          dY<MAX_ERROR && dY>-MAX_ERROR &&
137
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
138
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
139

  
140
      dX = mQuats[i].get0() + rX;
141
      dY = mQuats[i].get1() + rY;
142
      dZ = mQuats[i].get2() + rZ;
143
      dW = mQuats[i].get3() + rW;
144

  
145
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
146
          dY<MAX_ERROR && dY>-MAX_ERROR &&
147
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
148
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
149
      }
150

  
151
    return -1;
152
    }
153

  
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

  
156
  private int getMultQuat(int index1, int index2)
157
    {
158
    if( mQuatMult==null )
159
      {
160
      mQuatMult = new int[mNumQuats][mNumQuats];
161

  
162
      for(int i=0; i<mNumQuats; i++)
163
        for(int j=0; j<mNumQuats; j++) mQuatMult[i][j] = -1;
164
      }
165

  
166
    if( index1<mNumQuats && index2<mNumQuats )
167
      {
168
      if( mQuatMult[index1][index2]==-1 ) mQuatMult[index1][index2] = mulQuat(index1,index2);
169
      return mQuatMult[index1][index2];
170
      }
171

  
172

  
173
android.util.Log.e("D", "error in getMulQuat: index1="+index1+" index2="+index2+" numQuats="+mNumQuats);
174

  
175

  
176
    return -2;
177
    }
178

  
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

  
181
  private boolean belongsToMove(int cubit, int axis, int layer)
182
    {
183
    return mRotRow[cubit][axis] == layer;
184
    }
185

  
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187
// assumption: all layers have the same basicAngles!
188

  
189
  private int insertAllChildren(int index, byte level)
190
    {
191
    int ret = 0;
192
    int[] quats = getQuats(index);
193
    int numQuats = quats.length;
194
    int[] tmpQuats = new int[numQuats];
195
    byte newLevel = (byte)(level+1);
196
    boolean[] belongs = new boolean[mNumCubits];
197
    int quatBasis = 0;
198

  
199
    for(int ax=0; ax<mNumAxis; ax++)
200
      {
201
      for(int layer=0; layer<mNumLayers[ax]; layer++)
202
        {
203
        for(int cubit=0; cubit<mNumCubits; cubit++)
204
          belongs[cubit] = belongsToMove(cubit,ax,layer);
205

  
206
        int maxAngle = mAngles[ax][layer];
207

  
208
        for(int angle=1; angle<maxAngle; angle++ )
209
          {
210
          System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
211
          int quat = quatBasis + angle;
212

  
213
          for(int cubit=0; cubit<mNumCubits; cubit++)
214
            if( belongs[cubit] )
215
              {
216
              int currQuat = tmpQuats[cubit];
217
              int newQuat = getMultQuat(currQuat,quat);
218
              tmpQuats[cubit] = newQuat;
219
              }
220

  
221
android.util.Log.e("D", "quat: "+quat+" numAxis="+mNumAxis+" numLayers="+mNumLayers[ax]+" maxAngle="+maxAngle);
222

  
223
          int childIndex = getIndex(tmpQuats);
224
          if( mTablebase.insertUnpacked(childIndex,newLevel) ) ret++;
225
          }
226
        }
227

  
228
      quatBasis += (mAngles[ax][0]-1);
229
      }
230

  
231
    return ret;
232
    }
233

  
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

  
236
  public void createTablebase()
237
    {
238
    mTablebase = new Tablebase(mSize);
239
    mTablebase.insertUnpacked(0,(byte)0);
240

  
241
    int numInserted;
242
    byte insertingLevel = 0;
243

  
244
    do
245
      {
246
      numInserted = 0;
247

  
248
      for(int i=0; i<mSize; i++)
249
        {
250
        byte level = mTablebase.retrieveUnpacked(i);
251
        if( level==insertingLevel ) numInserted += insertAllChildren(i,level);
252
        }
253

  
254
      insertingLevel++;
255

  
256
android.util.Log.e("D", "inserted "+numInserted+" positions at level "+insertingLevel);
257
      }
258
    while( numInserted>0 );
259
    }
260
}
src/main/java/org/distorted/objectlib/tablebases/TablebasesPyraminxDuo.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.tablebases;
11

  
12
import static org.distorted.objectlib.main.TwistyObject.SQ2;
13

  
14
import org.distorted.library.type.Static3D;
15
import org.distorted.objectlib.objects.TwistyPyraminxDuo;
16

  
17
///////////////////////////////////////////////////////////////////////////////////////////////////
18

  
19
public class TablebasesPyraminxDuo extends TablebasesCreator
20
{
21
  int[][] getBasicAngles()
22
    {
23
    int[] tmp = {3,3};
24
    return new int[][] { tmp,tmp,tmp,tmp };
25
    }
26

  
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

  
29
  Static3D[] getRotationAxis()
30
    {
31
    return TwistyPyraminxDuo.ROT_AXIS;
32
    }
33

  
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35

  
36
  float[][] getPosition()
37
    {
38
    return new float[][]
39
         {
40
           { 0.000f, -SQ2/2, 1.000f },
41
           { 0.000f, -SQ2/2,-1.000f },
42
           {-1.000f,  SQ2/2, 0.000f },
43
           { 1.000f,  SQ2/2, 0.000f },
44

  
45
           { 0.000f,  SQ2/6, 1.0f/3 },
46
           { 0.000f,  SQ2/6,-1.0f/3 },
47
           {-1.0f/3, -SQ2/6, 0.000f },
48
           { 1.0f/3, -SQ2/6, 0.000f },
49
         };
50
    }
51

  
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53

  
54
  float[][] getCuts()
55
    {
56
    float[] cut = { 0.0f };
57
    return new float[][] { cut,cut,cut,cut };
58
    }
59

  
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61
// specifically for the tablebase
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

  
64
  int getSize()
65
    {
66
    return 324;  // see https://www.jaapsch.net/puzzles/pyraduo.htm
67
    }
68

  
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

  
71
  int[] getQuats(int index)
72
    {
73
    int c = index%4; index/=4;
74
    int b3= index%3; index/=3;
75
    int b2= index%3; index/=3;
76
    int b1= index%3; index/=3;
77
    int b0= index%3;
78

  
79
    // we don't need to care about the values of the last 3 quats, but do include them.
80
    int[] quats = new int[8];
81

  
82
    switch(c)
83
      {
84
      case 0: quats[4] = 2; break;
85
      case 1: quats[4] = 3; break;
86
      case 2: quats[4] = 4; break;
87
      case 3: quats[4] = 5; break;
88
      }
89

  
90
    switch(b3)
91
      {
92
      case 0: quats[3] = 0; break;
93
      case 1: quats[3] = 5; break;
94
      case 2: quats[3] = 6; break;
95
      }
96

  
97
    switch(b2)
98
      {
99
      case 0: quats[2] = 0; break;
100
      case 1: quats[2] = 7; break;
101
      case 2: quats[2] = 8; break;
102
      }
103

  
104
    switch(b1)
105
      {
106
      case 0: quats[1] = 0; break;
107
      case 1: quats[1] = 1; break;
108
      case 2: quats[1] = 2; break;
109
      }
110

  
111
    switch(b0)
112
      {
113
      case 0: quats[0] = 0; break;
114
      case 1: quats[0] = 3; break;
115
      case 2: quats[0] = 4; break;
116
      }
117

  
118
    return quats;
119
    }
120

  
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

  
123
  private int computeCornerTwistFromQuat(int quat)
124
    {
125
    switch(quat)
126
      {
127
      case 0: case 9: case 10: case 11: return 0;
128
      case 1: case 3: case  5: case  7: return 1;
129
      case 2: case 4: case  6: case  8: return 2;
130
      }
131

  
132
    return -1;
133
    }
134

  
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

  
137
  int getIndex(int[] quats)
138
    {
139
    int b0 = computeCornerTwistFromQuat(quats[0]);
140
    int b1 = computeCornerTwistFromQuat(quats[1]);
141
    int b2 = computeCornerTwistFromQuat(quats[2]);
142
    int b3 = computeCornerTwistFromQuat(quats[3]);
143

  
144
    int c = -1;
145
    switch(quats[4])
146
      {
147
      case  0: case  1: case  2: c=0; break;
148
      case  3: case  6: case  9: c=1; break;
149
      case  4: case  7: case 11: c=2; break;
150
      case  5: case  8: case 10: c=3; break;
151
      }
152

  
153
    int ret = c + 4*(b3 + 3*(b2 + 3*(b1 + 3*b0)));
154

  
155
    return ret;
156
    }
157
}  
158

  

Also available in: Unified diff