Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / tablebases / TablebasesAbstract.java @ e1e92738

1 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 3103c3c8 Leszek Koltunski
import org.distorted.objectlib.helpers.OperatingSystemInterface;
16 a110ebe1 Leszek Koltunski
import org.distorted.objectlib.helpers.QuatGroupGenerator;
17
18 352b3356 Leszek Koltunski
import java.io.ByteArrayOutputStream;
19
import java.io.IOException;
20
import java.io.InputStream;
21 bf5c802b Leszek Koltunski
import java.util.ArrayList;
22 3addecce Leszek Koltunski
import java.util.Random;
23 bf5c802b Leszek Koltunski
24 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
25
26 1725b607 Leszek Koltunski
public abstract class TablebasesAbstract
27 a110ebe1 Leszek Koltunski
{
28
  private final Static3D[] mAxis;
29 c0266cb1 Leszek Koltunski
  private final int mSize, mMinScramble;
30 a110ebe1 Leszek Koltunski
  private final int[][] mAngles;
31
  private final int[] mNumLayers;
32
  private final int mNumQuats;
33
  private final Static4D[] mQuats;
34
  private final float[][] mCuts;
35
  private final int[] mNumCuts;
36 b4111717 Leszek Koltunski
37 a110ebe1 Leszek Koltunski
  private int[][] mQuatMult;
38 9e7ff8d2 Leszek Koltunski
  private int[] mInvertedQuat;
39 a110ebe1 Leszek Koltunski
40 15d1f6ad Leszek Koltunski
  Tablebase mTablebase;
41 db2ed801 Leszek Koltunski
  boolean mInitialized;
42
43 bdcb662f Leszek Koltunski
  final int mScalingFactor;
44
  final int mNumAxis;
45
  final float[][] mPosition;
46
  final int[][] mRotRow;
47
  final int mNumCubits;
48
  final boolean[][] mRotatable;
49 15d1f6ad Leszek Koltunski
50 b4111717 Leszek Koltunski
  private static final float[] mTmp = new float[4];
51
52 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
53
54
  abstract int[][] getBasicAngles();
55
  abstract Static3D[] getRotationAxis();
56
  abstract float[][] getPosition();
57
  abstract float[][] getCuts();
58
59 b4111717 Leszek Koltunski
  abstract boolean[][] getRotatable();
60
61 c0266cb1 Leszek Koltunski
  abstract int getMinScramble();
62 b4111717 Leszek Koltunski
  abstract int getSize();
63
  abstract int[] getQuats(int index);
64
  abstract int getIndex(int[] quats);
65
66 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
67
68 1725b607 Leszek Koltunski
  public TablebasesAbstract()
69 a110ebe1 Leszek Koltunski
    {
70
    mSize = getSize();
71 c0266cb1 Leszek Koltunski
    mMinScramble = getMinScramble();
72 a110ebe1 Leszek Koltunski
    mAngles = getBasicAngles();
73
    mAxis = getRotationAxis();
74
    mNumAxis = mAxis.length;
75
    mNumLayers = new int[mNumAxis];
76
    for(int i=0; i<mNumAxis; i++) mNumLayers[i] = mAngles[i].length;
77
    mQuats = QuatGroupGenerator.computeGroup(mAxis,mAngles);
78
    mNumQuats = mQuats.length;
79
    mPosition = getPosition();
80
    mNumCubits = mPosition.length;
81 b4111717 Leszek Koltunski
    mRotatable = getRotatable();
82 a110ebe1 Leszek Koltunski
    mCuts = getCuts();
83
    mNumCuts = new int[mNumAxis];
84
85 3addecce Leszek Koltunski
    int scaling = 0;
86
87 a110ebe1 Leszek Koltunski
    for(int i=0; i<mNumAxis; i++)
88
      {
89
      mNumCuts[i] = (mCuts==null || mCuts[i]==null ? 0 : mCuts[i].length);
90 3addecce Leszek Koltunski
      int numLayers = mNumLayers[i];
91
      for(int j=0; j<numLayers; j++) scaling+=(mAngles[i][j]-1);
92 a110ebe1 Leszek Koltunski
      }
93
94 3addecce Leszek Koltunski
    mScalingFactor = scaling;
95 a110ebe1 Leszek Koltunski
    mRotRow = new int[mNumCubits][mNumAxis];
96 5e501d98 Leszek Koltunski
    mInitialized = false;
97 352b3356 Leszek Koltunski
    }
98
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
101 3103c3c8 Leszek Koltunski
  public TablebasesAbstract(OperatingSystemInterface os, int resource)
102 352b3356 Leszek Koltunski
    {
103
    this();
104
105 f9980f6a Leszek Koltunski
    mInitialized = true;
106 3103c3c8 Leszek Koltunski
    InputStream stream = os.openLocalFile(resource);
107 352b3356 Leszek Koltunski
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
108
109
    int nRead;
110
    byte[] tmp = new byte[16384];
111
112
    try
113
      {
114
      while ((nRead = stream.read(tmp, 0, tmp.length)) != -1)
115
        {
116
        buffer.write(tmp, 0, nRead);
117
        }
118 1725b607 Leszek Koltunski
      stream.close();
119 352b3356 Leszek Koltunski
      byte[] data = buffer.toByteArray();
120 1725b607 Leszek Koltunski
      buffer.close();
121 352b3356 Leszek Koltunski
      mTablebase = new Tablebase(data);
122
      }
123
    catch(IOException ex)
124
      {
125
      mInitialized = false;
126
      }
127 a110ebe1 Leszek Koltunski
    }
128
129 3feba94e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
130
131
  int computeBitLayer(int ax, int layer)
132
    {
133
    return (1<<layer);
134
    }
135
136 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138 bdcb662f Leszek Koltunski
  int computeRow(float[] pos, int quat, int axisIndex)
139 a110ebe1 Leszek Koltunski
    {
140
    int ret=0;
141
    int len = pos.length/3;
142
    Static3D axis = mAxis[axisIndex];
143
    float axisX = axis.get0();
144
    float axisY = axis.get1();
145
    float axisZ = axis.get2();
146
    float casted, xoff=0, yoff=0, zoff=0;
147 b4111717 Leszek Koltunski
    Static4D q = mQuats[quat];
148 a110ebe1 Leszek Koltunski
149
    for(int i=0; i<len; i++)
150
      {
151 b4111717 Leszek Koltunski
      QuatHelper.rotateVectorByQuat(mTmp,pos[3*i],pos[3*i+1],pos[3*i+2],1.0f,q);
152
      casted = (mTmp[0]+xoff)*axisX + (mTmp[1]+yoff)*axisY + (mTmp[2]+zoff)*axisZ;
153 a110ebe1 Leszek Koltunski
      ret |= computeSingleRow(axisIndex,casted);
154
      }
155
156
    return ret;
157
    }
158
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160
161
  private int computeSingleRow(int axisIndex,float casted)
162
    {
163
    int num = mNumCuts[axisIndex];
164
165
    for(int i=0; i<num; i++)
166
      {
167
      if( casted<mCuts[axisIndex][i] ) return (1<<i);
168
      }
169
170
    return (1<<num);
171
    }
172
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174
// remember about the double cover or unit quaternions!
175
176 398f2870 Leszek Koltunski
  public static int mulQuat(int q1, int q2, Static4D[] quats)
177 a110ebe1 Leszek Koltunski
    {
178 398f2870 Leszek Koltunski
    int numQuats = quats.length;
179
    Static4D result = QuatHelper.quatMultiply(quats[q1],quats[q2]);
180 a110ebe1 Leszek Koltunski
181
    float rX = result.get0();
182
    float rY = result.get1();
183
    float rZ = result.get2();
184
    float rW = result.get3();
185
186
    final float MAX_ERROR = 0.1f;
187
    float dX,dY,dZ,dW;
188
189 398f2870 Leszek Koltunski
    for(int i=0; i<numQuats; i++)
190 a110ebe1 Leszek Koltunski
      {
191 398f2870 Leszek Koltunski
      dX = quats[i].get0() - rX;
192
      dY = quats[i].get1() - rY;
193
      dZ = quats[i].get2() - rZ;
194
      dW = quats[i].get3() - rW;
195 a110ebe1 Leszek Koltunski
196
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
197
          dY<MAX_ERROR && dY>-MAX_ERROR &&
198
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
199
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
200
201 398f2870 Leszek Koltunski
      dX = quats[i].get0() + rX;
202
      dY = quats[i].get1() + rY;
203
      dZ = quats[i].get2() + rZ;
204
      dW = quats[i].get3() + rW;
205 a110ebe1 Leszek Koltunski
206
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
207
          dY<MAX_ERROR && dY>-MAX_ERROR &&
208
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
209
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
210
      }
211
212
    return -1;
213
    }
214
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216
217 bdcb662f Leszek Koltunski
  int getMultQuat(int index1, int index2)
218 a110ebe1 Leszek Koltunski
    {
219
    if( mQuatMult==null )
220
      {
221
      mQuatMult = new int[mNumQuats][mNumQuats];
222
223
      for(int i=0; i<mNumQuats; i++)
224
        for(int j=0; j<mNumQuats; j++) mQuatMult[i][j] = -1;
225
      }
226
227
    if( index1<mNumQuats && index2<mNumQuats )
228
      {
229 398f2870 Leszek Koltunski
      if( mQuatMult[index1][index2]==-1 ) mQuatMult[index1][index2] = mulQuat(index1,index2, mQuats);
230 a110ebe1 Leszek Koltunski
      return mQuatMult[index1][index2];
231
      }
232
233
    return -2;
234
    }
235
236 9e7ff8d2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
237
238
  int getInvertedQuat(int index)
239
    {
240
    if( mInvertedQuat==null )
241
      {
242
      mInvertedQuat = new int[mNumQuats];
243
244
      for(int i=0; i<mNumQuats; i++)
245
        for(int j=0; j<mNumQuats; j++)
246
          {
247
          int result = getMultQuat(i,j);
248
249
          if( result==0 )
250
            {
251
            mInvertedQuat[i] = j;
252
            break;
253
            }
254
          }
255
      }
256
257
    return mInvertedQuat[index];
258
    }
259
260 a110ebe1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
261
// assumption: all layers have the same basicAngles!
262
263
  private int insertAllChildren(int index, byte level)
264
    {
265
    int ret = 0;
266
    int[] quats = getQuats(index);
267
    int numQuats = quats.length;
268
    int[] tmpQuats = new int[numQuats];
269
    byte newLevel = (byte)(level+1);
270
    int quatBasis = 0;
271
272 ce7202ef Leszek Koltunski
    for(int ax=0; ax<mNumAxis; ax++)
273
      for(int cubit=0; cubit<mNumCubits; cubit++)
274
        mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
275
276 a110ebe1 Leszek Koltunski
    for(int ax=0; ax<mNumAxis; ax++)
277
      {
278
      for(int layer=0; layer<mNumLayers[ax]; layer++)
279
        {
280 b4111717 Leszek Koltunski
        if( !mRotatable[ax][layer] ) continue;
281 3feba94e Leszek Koltunski
        int bitLayer = computeBitLayer(ax,layer);
282 a110ebe1 Leszek Koltunski
        int maxAngle = mAngles[ax][layer];
283
284
        for(int angle=1; angle<maxAngle; angle++ )
285
          {
286
          System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
287
          int quat = quatBasis + angle;
288
289
          for(int cubit=0; cubit<mNumCubits; cubit++)
290 3feba94e Leszek Koltunski
            if( (mRotRow[cubit][ax] & bitLayer) != 0 )
291 a110ebe1 Leszek Koltunski
              {
292
              int currQuat = tmpQuats[cubit];
293 b4111717 Leszek Koltunski
              int newQuat = getMultQuat(quat,currQuat);
294 a110ebe1 Leszek Koltunski
              tmpQuats[cubit] = newQuat;
295
              }
296
297
          int childIndex = getIndex(tmpQuats);
298 c64217f7 Leszek Koltunski
          if( mTablebase.insertUnpacked(childIndex,newLevel) )
299
            {
300
            //android.util.Log.e("D", newLevel+" parent:"+index+" index: "+childIndex+" ax="+ax+" layer="+layer+" angle="+angle);
301
            ret++;
302
            }
303
          else
304
            {
305
            //android.util.Log.d("D", newLevel+" parent:"+index+" index: "+childIndex+" ax="+ax+" layer="+layer+" angle="+angle);
306
            }
307 a110ebe1 Leszek Koltunski
          }
308
        }
309
310
      quatBasis += (mAngles[ax][0]-1);
311
      }
312
313
    return ret;
314
    }
315
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317
318 5e30b196 Leszek Koltunski
  public void createTablebase(int maxLevel)
319 a110ebe1 Leszek Koltunski
    {
320
    mTablebase = new Tablebase(mSize);
321 5b9f1cec Leszek Koltunski
    int[] solved = getSolvedIndices();
322
    int numSolved = solved.length;
323
    for(int s : solved ) mTablebase.insertUnpacked(s,(byte)0);
324 a110ebe1 Leszek Koltunski
325 5b9f1cec Leszek Koltunski
    int numInserted, totalInserted=numSolved;
326 a110ebe1 Leszek Koltunski
    byte insertingLevel = 0;
327
328 462911fd Leszek Koltunski
    android.util.Log.e("D", "creating tablebase of size "+mSize);
329
330 a110ebe1 Leszek Koltunski
    do
331
      {
332
      numInserted = 0;
333
334
      for(int i=0; i<mSize; i++)
335
        {
336
        byte level = mTablebase.retrieveUnpacked(i);
337
        if( level==insertingLevel ) numInserted += insertAllChildren(i,level);
338
        }
339
340
      insertingLevel++;
341 f9980f6a Leszek Koltunski
      totalInserted += numInserted;
342 bf5c802b Leszek Koltunski
      android.util.Log.e("D", "inserted "+numInserted+" positions at level "+insertingLevel);
343 a110ebe1 Leszek Koltunski
      }
344 5e30b196 Leszek Koltunski
    while( numInserted>0 && insertingLevel!=maxLevel );
345 bf5c802b Leszek Koltunski
346 f9980f6a Leszek Koltunski
    android.util.Log.e("D", "total Inserted: "+totalInserted);
347 5e30b196 Leszek Koltunski
    }
348
349 5b9f1cec Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
350
351
  int[] getSolvedIndices()
352
    {
353
    return new int[] {0};
354
    }
355
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357
358
  boolean isSolved(int index)
359
    {
360
    return index==0;
361
    }
362
363 5e30b196 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
364
365
  public void pack()
366
    {
367 462911fd Leszek Koltunski
    android.util.Log.e("D", "packing...");
368 bf5c802b Leszek Koltunski
    mTablebase.pack();
369 462911fd Leszek Koltunski
    android.util.Log.e("D", "all done");
370 5e501d98 Leszek Koltunski
    mInitialized = true;
371 462911fd Leszek Koltunski
    }
372
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374
375 15d1f6ad Leszek Koltunski
  public byte[][] getPacked()
376 462911fd Leszek Koltunski
    {
377 b8a7c09d Leszek Koltunski
    if( !mInitialized )
378
      {
379
      createTablebase(-1);
380
      pack();
381
      }
382 15d1f6ad Leszek Koltunski
383 b8a7c09d Leszek Koltunski
    byte[] data = mTablebase.getPacked();
384 15d1f6ad Leszek Koltunski
    return new byte[][] { data };
385 a110ebe1 Leszek Koltunski
    }
386 3ee79c9c Leszek Koltunski
387 bdcb662f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
388
389
  void convertMoves(int[][] moves)
390
    {
391
    for(int[] move : moves )
392
      {
393 45dc5cd7 Leszek Koltunski
      int[] m = newMove(move[0],move[1],move[2]);
394 bdcb662f Leszek Koltunski
395 45dc5cd7 Leszek Koltunski
      move[0] = m[0];
396
      move[1] = m[1];
397
      move[2] = m[2];
398 bdcb662f Leszek Koltunski
      }
399
    }
400
401 3ee79c9c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
402
403 3feba94e Leszek Koltunski
  int[] newMove(int ax, int layer, int angle)
404 3ee79c9c Leszek Koltunski
    {
405 3feba94e Leszek Koltunski
    int maxAngle = mAngles[ax][layer];
406 3ee79c9c Leszek Koltunski
    angle = maxAngle-angle;
407
    if( angle> 0.5f*maxAngle ) angle -= maxAngle;
408
409 3feba94e Leszek Koltunski
    return new int[] { ax, computeBitLayer(ax,layer), angle };
410 bf5c802b Leszek Koltunski
    }
411
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413
414 ca2ba7a1 Leszek Koltunski
  int[][] convertMovesFromArray(ArrayList<int[]> moves)
415 bf5c802b Leszek Koltunski
    {
416
    int len = moves.size();
417
    int[][] ret = new int[len][];
418
    for(int i=0; i<len; i++) ret[i] = moves.get(i);
419
    return ret;
420 3ee79c9c Leszek Koltunski
    }
421
422 3addecce Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
423
424 bdcb662f Leszek Koltunski
  void getNextAxisLayerAngleQuat(int[] data)
425 3addecce Leszek Koltunski
    {
426
    int axis = data[0];
427
    int layer= data[1];
428
    int angle= data[2];
429
430
    if( angle< mAngles[axis][layer]-1 ) data[2]++;
431
    else
432
      {
433
      data[2] = 1;
434
435
      if( layer< mNumLayers[axis]-1 ) data[1]++;
436
      else
437
        {
438
        data[1] = 0;
439
        data[0] = (axis<mNumAxis-1) ? axis+1 : 0;
440
        }
441
      }
442 971a184e Leszek Koltunski
443
    data[3] = data[2];
444
    for(int i=0; i<data[0]; i++) data[3] += (mAngles[i][0]-1);
445 3addecce Leszek Koltunski
    }
446
447 3ee79c9c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
448
449 6d637f71 Leszek Koltunski
  int[][] extraInfo(int[][] moves, int[] extra)
450
    {
451
    return moves;
452
    }
453
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455
456 00e83f23 Leszek Koltunski
  public int[][] solution(int index, int[] extra, OperatingSystemInterface osi)
457 3ee79c9c Leszek Koltunski
    {
458 352b3356 Leszek Koltunski
    if( !mInitialized ) return null;
459
460 971a184e Leszek Koltunski
    int[] data = new int[4];
461 431ee33b Leszek Koltunski
    byte level = mTablebase.retrievePacked(index);
462 bf5c802b Leszek Koltunski
    ArrayList<int[]> moves = new ArrayList<>();
463 3ee79c9c Leszek Koltunski
    int[] quats = getQuats(index);
464
    int numQuats = quats.length;
465
    int[] tmpQuats = new int[numQuats];
466
467 5b9f1cec Leszek Koltunski
    while( !isSolved(index) )
468 3ee79c9c Leszek Koltunski
      {
469 7c1a110c Leszek Koltunski
      boolean found = false;
470
471 3addecce Leszek Koltunski
      data[0]=0;
472
      data[1]=0;
473
      data[2]=1;
474 971a184e Leszek Koltunski
      data[3]=1;
475 3addecce Leszek Koltunski
476 ce7202ef Leszek Koltunski
      for(int ax=0; ax<mNumAxis; ax++)
477
        for(int cubit=0; cubit<mNumCubits; cubit++)
478
          mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
479
480 3addecce Leszek Koltunski
      for(int s=0; s<mScalingFactor && !found; s++)
481 3ee79c9c Leszek Koltunski
        {
482 3addecce Leszek Koltunski
        int ax    = data[0];
483
        int layer = data[1];
484
        int angle = data[2];
485 971a184e Leszek Koltunski
        int quat  = data[3];
486 3ee79c9c Leszek Koltunski
487 3addecce Leszek Koltunski
        if( mRotatable[ax][layer] )
488 3ee79c9c Leszek Koltunski
          {
489 3feba94e Leszek Koltunski
          int bitLayer = computeBitLayer(ax,layer);
490 3addecce Leszek Koltunski
          System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
491 3ee79c9c Leszek Koltunski
492 3addecce Leszek Koltunski
          for(int cubit=0; cubit<mNumCubits; cubit++)
493 3feba94e Leszek Koltunski
            if( (mRotRow[cubit][ax] & bitLayer) != 0 )
494 3ee79c9c Leszek Koltunski
              {
495 3addecce Leszek Koltunski
              int currQuat = tmpQuats[cubit];
496
              int newQuat = getMultQuat(quat,currQuat);
497
              tmpQuats[cubit] = newQuat;
498 3ee79c9c Leszek Koltunski
              }
499 3addecce Leszek Koltunski
500
          int childIndex = getIndex(tmpQuats);
501
          byte newLevel = mTablebase.retrievePacked(childIndex);
502
503
          if( ((newLevel-level+1)%3) == 0 )
504
            {
505 5b9f1cec Leszek Koltunski
            int[] tmpMove = newMove(ax,layer,angle);
506
            moves.add(tmpMove);
507 3addecce Leszek Koltunski
            index = childIndex;
508
            level = (level==0 ? 2 : (byte)(level-1));
509
            found = true;
510 3ee79c9c Leszek Koltunski
            }
511
          }
512
513 971a184e Leszek Koltunski
        getNextAxisLayerAngleQuat(data);
514 3ee79c9c Leszek Koltunski
        }
515
516
      quats = getQuats(index);
517 7c1a110c Leszek Koltunski
518
      if( !found )
519
        {
520 00e83f23 Leszek Koltunski
        if( osi!=null ) osi.reportError("solution error: no move found!"+index);
521 7c1a110c Leszek Koltunski
        return null;
522
        }
523 3ee79c9c Leszek Koltunski
      }
524
525 45dc5cd7 Leszek Koltunski
    int[][] ret = convertMovesFromArray(moves);
526 6d637f71 Leszek Koltunski
    return extraInfo(ret,extra);
527 3ee79c9c Leszek Koltunski
    }
528 462911fd Leszek Koltunski
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530
531 c0266cb1 Leszek Koltunski
  public void scramble(Random rnd, int depth, int[][] scramble)
532 462911fd Leszek Koltunski
    {
533 c0266cb1 Leszek Koltunski
    if( !mInitialized ) return;
534 3addecce Leszek Koltunski
535 c0266cb1 Leszek Koltunski
    int solDepth = 0;
536
    int scraLen = scramble.length;
537
    if( depth>mMinScramble ) depth = mMinScramble;
538 462911fd Leszek Koltunski
539 6d637f71 Leszek Koltunski
    int[] cornerTwist = new int[4];
540
    for(int i=0; i<4; i++) cornerTwist[i] = (rnd.nextInt(3)-1);
541
542 c0266cb1 Leszek Koltunski
    while( solDepth<depth )
543 462911fd Leszek Koltunski
      {
544 c0266cb1 Leszek Koltunski
      int randomPosition = rnd.nextInt(mSize-1);
545 00e83f23 Leszek Koltunski
      int[][] sol = solution(randomPosition,cornerTwist,null);
546 b60d1cba Leszek Koltunski
      solDepth = (sol!=null ? sol.length : 0);
547 ce7202ef Leszek Koltunski
548 c0266cb1 Leszek Koltunski
      if( solDepth>=depth )
549 462911fd Leszek Koltunski
        {
550 c0266cb1 Leszek Koltunski
        int num = Math.min(scraLen,solDepth);
551 462911fd Leszek Koltunski
552 c0266cb1 Leszek Koltunski
        for(int i=0; i<num; i++)
553 462911fd Leszek Koltunski
          {
554 c0266cb1 Leszek Koltunski
          int[] source = sol[solDepth-1-i];
555
          scramble[i][0] = source[0];
556 00057bb1 Leszek Koltunski
          scramble[i][1] = source[1];
557 c0266cb1 Leszek Koltunski
          scramble[i][2] =-source[2];
558 462911fd Leszek Koltunski
          }
559
        }
560
      }
561
    }
562 74cc695a Leszek Koltunski
563 5b9f1cec Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
564
// TESTING
565 74cc695a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
566
567
  public boolean test(int index)
568
    {
569
    if( !mInitialized ) return false;
570
571
    int[] data = new int[4];
572
    byte level = mTablebase.retrievePacked(index);
573
    int[] quats = getQuats(index);
574
    int numQuats = quats.length;
575
    int[] tmpQuats = new int[numQuats];
576
577
    data[0]=0;
578
    data[1]=0;
579
    data[2]=1;
580
    data[3]=1;
581
582
    for(int ax=0; ax<mNumAxis; ax++)
583
      for(int cubit=0; cubit<mNumCubits; cubit++)
584
        mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
585
586
    for(int s=0; s<mScalingFactor; s++)
587
      {
588
      int ax    = data[0];
589
      int layer = data[1];
590
      int quat  = data[3];
591
592
      if( mRotatable[ax][layer] )
593
        {
594 3feba94e Leszek Koltunski
        int bitLayer = computeBitLayer(ax,layer);
595 74cc695a Leszek Koltunski
        System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
596
597
        for(int cubit=0; cubit<mNumCubits; cubit++)
598 3feba94e Leszek Koltunski
          if( (mRotRow[cubit][ax] & bitLayer) != 0 )
599 74cc695a Leszek Koltunski
            {
600
            int currQuat = tmpQuats[cubit];
601
            int newQuat = getMultQuat(quat,currQuat);
602
            tmpQuats[cubit] = newQuat;
603
            }
604
605
        int childIndex = getIndex(tmpQuats);
606
        byte newLevel = mTablebase.retrievePacked(childIndex);
607
608
        if( ((newLevel-level+1)%3) == 0 ) return true;
609
        }
610
611
      getNextAxisLayerAngleQuat(data);
612
      }
613
614
    return false;
615
    }
616 5e30b196 Leszek Koltunski
617 5b9f1cec Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
618
619 ca2ba7a1 Leszek Koltunski
  public void test(OperatingSystemInterface os)
620 5b9f1cec Leszek Koltunski
    {
621 c64217f7 Leszek Koltunski
    int index = 252373232;
622
    int[] q = getQuats(index);
623
    TablebaseHelpers.displayTable(q , "QUATS ");
624 5b9f1cec Leszek Koltunski
    }
625 a110ebe1 Leszek Koltunski
}