Project

General

Profile

Download (10.3 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / tablebases / TablebasesCreator.java @ 3ee79c9c

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 final boolean[][] mRotatable;
35

    
36
  private int[][] mQuatMult;
37

    
38
  private static final float[] mTmp = new float[4];
39

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

    
42
  abstract int[][] getBasicAngles();
43
  abstract Static3D[] getRotationAxis();
44
  abstract float[][] getPosition();
45
  abstract float[][] getCuts();
46

    
47
  abstract boolean[][] getRotatable();
48

    
49
  abstract int getSize();
50
  abstract int[] getQuats(int index);
51
  abstract int getIndex(int[] quats);
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

    
55
  public TablebasesCreator()
56
    {
57
    mSize = getSize();
58
    mAngles = getBasicAngles();
59
    mAxis = getRotationAxis();
60
    mNumAxis = mAxis.length;
61
    mNumLayers = new int[mNumAxis];
62
    for(int i=0; i<mNumAxis; i++) mNumLayers[i] = mAngles[i].length;
63
    mQuats = QuatGroupGenerator.computeGroup(mAxis,mAngles);
64
    mNumQuats = mQuats.length;
65
    mPosition = getPosition();
66
    mNumCubits = mPosition.length;
67
    mRotatable = getRotatable();
68
    mCuts = getCuts();
69
    mNumCuts = new int[mNumAxis];
70

    
71
    for(int i=0; i<mNumAxis; i++)
72
      {
73
      mNumCuts[i] = (mCuts==null || mCuts[i]==null ? 0 : mCuts[i].length);
74
      }
75

    
76
    mRotRow = new int[mNumCubits][mNumAxis];
77
    }
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

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

    
92
    for(int i=0; i<len; i++)
93
      {
94
      QuatHelper.rotateVectorByQuat(mTmp,pos[3*i],pos[3*i+1],pos[3*i+2],1.0f,q);
95
      casted = (mTmp[0]+xoff)*axisX + (mTmp[1]+yoff)*axisY + (mTmp[2]+zoff)*axisZ;
96
      ret |= computeSingleRow(axisIndex,casted);
97
      }
98

    
99
    return ret;
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  private int computeSingleRow(int axisIndex,float casted)
105
    {
106
    int num = mNumCuts[axisIndex];
107

    
108
    for(int i=0; i<num; i++)
109
      {
110
      if( casted<mCuts[axisIndex][i] ) return (1<<i);
111
      }
112

    
113
    return (1<<num);
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117
// remember about the double cover or unit quaternions!
118

    
119
  private int mulQuat(int q1, int q2)
120
    {
121
    Static4D result = QuatHelper.quatMultiply(mQuats[q1],mQuats[q2]);
122

    
123
    float rX = result.get0();
124
    float rY = result.get1();
125
    float rZ = result.get2();
126
    float rW = result.get3();
127

    
128
    final float MAX_ERROR = 0.1f;
129
    float dX,dY,dZ,dW;
130

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

    
138
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
139
          dY<MAX_ERROR && dY>-MAX_ERROR &&
140
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
141
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
142

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

    
148
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
149
          dY<MAX_ERROR && dY>-MAX_ERROR &&
150
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
151
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
152
      }
153

    
154
    return -1;
155
    }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  private int getMultQuat(int index1, int index2)
160
    {
161
    if( mQuatMult==null )
162
      {
163
      mQuatMult = new int[mNumQuats][mNumQuats];
164

    
165
      for(int i=0; i<mNumQuats; i++)
166
        for(int j=0; j<mNumQuats; j++) mQuatMult[i][j] = -1;
167
      }
168

    
169
    if( index1<mNumQuats && index2<mNumQuats )
170
      {
171
      if( mQuatMult[index1][index2]==-1 ) mQuatMult[index1][index2] = mulQuat(index1,index2);
172
      return mQuatMult[index1][index2];
173
      }
174

    
175
    return -2;
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

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

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

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

    
198
    for(int ax=0; ax<mNumAxis; ax++)
199
      {
200
      for(int layer=0; layer<mNumLayers[ax]; layer++)
201
        {
202
        if( !mRotatable[ax][layer] ) continue;
203
        int bitLayer = (1<<layer);
204

    
205
        for(int cubit=0; cubit<mNumCubits; cubit++)
206
          {
207
          mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
208
          belongs[cubit] = belongsToMove(cubit,ax,bitLayer);
209
          }
210

    
211
        int maxAngle = mAngles[ax][layer];
212

    
213
        for(int angle=1; angle<maxAngle; angle++ )
214
          {
215
          System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
216
          int quat = quatBasis + angle;
217

    
218
          for(int cubit=0; cubit<mNumCubits; cubit++)
219
            if( belongs[cubit] )
220
              {
221
              int currQuat = tmpQuats[cubit];
222
              int newQuat = getMultQuat(quat,currQuat);
223
              tmpQuats[cubit] = newQuat;
224
              }
225

    
226
          int childIndex = getIndex(tmpQuats);
227
          if( mTablebase.insertUnpacked(childIndex,newLevel) ) ret++;
228
          }
229
        }
230

    
231
      quatBasis += (mAngles[ax][0]-1);
232
      }
233

    
234
    return ret;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
  public void createTablebase()
240
    {
241
    mTablebase = new Tablebase(mSize);
242
    mTablebase.insertUnpacked(0,(byte)0);
243

    
244
    int numInserted;
245
    byte insertingLevel = 0;
246

    
247
    do
248
      {
249
      numInserted = 0;
250

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

    
257
      insertingLevel++;
258

    
259
      // android.util.Log.e("D", "inserted "+numInserted+" positions at level "+insertingLevel);
260
      }
261
    while( numInserted>0 );
262
    }
263

    
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265

    
266
  private void setupMove(int[] move, int axis, int layer, int angle)
267
    {
268
    int maxAngle = mAngles[axis][layer];
269
    angle = maxAngle-angle;
270
    if( angle> 0.5f*maxAngle ) angle -= maxAngle;
271

    
272
    move[0] = axis;
273
    move[1] = (1<<layer);
274
    move[2] = angle;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  public int[][] solution(int index)
280
    {
281
    byte level = mTablebase.retrieveUnpacked(index);
282
    int[][] moves = level>0 ? new int[level][3] : null;
283
    int currMove = 0;
284
    int quatBasis = 0;
285
    int[] quats = getQuats(index);
286
    int numQuats = quats.length;
287
    int[] tmpQuats = new int[numQuats];
288
    boolean[] belongs = new boolean[mNumCubits];
289

    
290
    while(level>0)
291
      {
292
      for(int ax=0; ax<mNumAxis; ax++)
293
        {
294
        int numLayers = mNumLayers[ax];
295
        int[] angles = mAngles[ax];
296

    
297
        for(int layer=0; layer<numLayers; layer++)
298
          {
299
          if( !mRotatable[ax][layer] ) continue;
300
          int bitLayer = (1<<layer);
301

    
302
          for(int cubit=0; cubit<mNumCubits; cubit++)
303
            {
304
            mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
305
            belongs[cubit] = belongsToMove(cubit,ax,bitLayer);
306
            }
307

    
308
          int maxAngle = angles[layer];
309

    
310
          for(int angle=1; angle<maxAngle; angle++ )
311
            {
312
            System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
313
            int quat = quatBasis + angle;
314

    
315
            for(int cubit=0; cubit<mNumCubits; cubit++)
316
              if( belongs[cubit] )
317
                {
318
                int currQuat = tmpQuats[cubit];
319
                int newQuat = getMultQuat(quat,currQuat);
320
                tmpQuats[cubit] = newQuat;
321
                }
322

    
323
            int childIndex = getIndex(tmpQuats);
324
            byte newLevel = mTablebase.retrieveUnpacked(childIndex);
325

    
326
            if( newLevel==level-1 )
327
              {
328
              setupMove(moves[currMove],ax,layer,angle);
329
              currMove++;
330

    
331
              angle=maxAngle;
332
              layer=numLayers;
333
              ax=mNumAxis;
334
              index = childIndex;
335
              level = newLevel;
336
              }
337
            }
338
          }
339

    
340
        quatBasis += (angles[0]-1);
341
        }
342

    
343
      quatBasis = 0;
344
      quats = getQuats(index);
345
      }
346

    
347
    return moves;
348
    }
349
}
(2-2/3)