Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObjectScrambler.java @ 4a5157a1

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objectlib.main;
21

    
22
import org.distorted.objectlib.helpers.ScrambleState;
23

    
24
import java.util.Random;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27

    
28
public class TwistyObjectScrambler
29
  {
30
  private final ScrambleState[] mStates;
31
  private final int mType;
32
  private final int mNumAxis;
33
  private final int[] mNumLayers;
34

    
35
  // type=0, i.e. main
36
  private int mCurrState;
37
  private int mIndexExcluded;
38
  private int[][] mScrambleTable;
39
  private int[] mNumOccurences;
40

    
41
  // type=1, i.e. the exception: Square-1
42
  private static final int BASIC_ANGLE = 12;
43
  private static final int LAST_SL = 0; // automatic rotations: last rot was a 'slash' i.e. along ROT_AXIS[1]
44
  private static final int LAST_UP = 1; // last rot was along ROT_AXIS[0], upper layer and forelast was a slash
45
  private static final int LAST_LO = 2; // last rot was along ROT_AXIS[0], lower layer and forelast was a slash
46
  private static final int LAST_UL = 3; // two last rots were along ROT_AXIS[0] (so the next must be a slash)
47

    
48
  private int[][] mPermittedAngles;
49
  private int[] mCornerQuat;
50
  private int mPermittedUp, mPermittedDo;
51
  private int[][] mBadCornerQuats;
52
  private int mLastRot;
53
  private int[][] mQuatMult;
54

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

    
57
  TwistyObjectScrambler(int type, int numAxis, int[] numLayers, ScrambleState[] states)
58
    {
59
    mType = type;
60
    mNumAxis = numAxis;
61
    mNumLayers = numLayers;
62
    mStates = states;
63

    
64
    if( mType==1 )
65
      {
66
      mPermittedAngles = new int[2][BASIC_ANGLE];
67
      mCornerQuat = new int[8];
68
      mLastRot = LAST_SL;
69
      }
70
    }
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73

    
74
  private void initializeScrambling()
75
    {
76
    if( mScrambleTable ==null )
77
      {
78
      mScrambleTable = new int[mNumAxis][];
79
      }
80
    if( mNumOccurences ==null )
81
      {
82
      int max=0;
83

    
84
      for (ScrambleState mState : mStates)
85
        {
86
        int tmp = mState.getTotal(-1);
87
        if (max < tmp) max = tmp;
88
        }
89

    
90
      mNumOccurences = new int[max];
91
      }
92

    
93
    for(int i=0; i<mNumAxis; i++)
94
      {
95
      int len = mNumLayers[i];
96
      mScrambleTable[i] = new int[len];
97
      for(int j=0; j<len; j++) mScrambleTable[i][j] = 0;
98
      }
99
    }
100

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102
// PUBLIC API
103

    
104
  private void randomizeNewScramble0(int[][] scramble, Random rnd, int curr, int total)
105
    {
106
    if( curr==0 )
107
      {
108
      mCurrState     = 0;
109
      mIndexExcluded =-1;
110
      initializeScrambling();
111
      }
112

    
113
    int[] info= mStates[mCurrState].getRandom(rnd, mIndexExcluded, mScrambleTable, mNumOccurences);
114

    
115
    scramble[curr][0] = info[0];
116
    scramble[curr][1] = info[1];
117
    scramble[curr][2] = info[2];
118

    
119
    mCurrState     = info[3];
120
    mIndexExcluded = info[0];
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// TYPE 1
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126
// QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128

    
129
  void initializeQuatMult()
130
    {
131
    mQuatMult = new int[][]
132
      {
133
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
134
        {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
135
        {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
136
        {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
137
        {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
138
        {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
139
        {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
140
        {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
141
        {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
142
        {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
143
        { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
144
        { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
145
        { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
146
        { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
147
        { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
148
        { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
149
        { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
150
        { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
151
        { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
152
        { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
153
        { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
154
        { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
155
        { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
156
        { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
157
      };
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161
// TYPE 1
162

    
163
  private boolean cornerIsUp(int index)
164
    {
165
    return ((index<4) ^ (mCornerQuat[index]>=12));
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
// TYPE 1
170

    
171
  private boolean cornerIsLeft(int index)
172
    {
173
    int q = mCornerQuat[index];
174

    
175
    switch(index)
176
      {
177
      case 0:
178
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
179
      case 1:
180
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
181
      case 2:
182
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
183
      case 3:
184
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
185
      }
186

    
187
    return false;
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
// TYPE 1
192

    
193
  private boolean quatIsBad(int quatIndex, int corner)
194
    {
195
    if( mBadCornerQuats ==null )
196
      {
197
      // quat indices that make corner cubits bandage the puzzle.
198
      mBadCornerQuats = new int[][] { { 2, 8,17,23}, { 5,11,14,20} };
199
      }
200

    
201
    int index = (corner%2);
202

    
203
    return ( quatIndex== mBadCornerQuats[index][0] ||
204
             quatIndex== mBadCornerQuats[index][1] ||
205
             quatIndex== mBadCornerQuats[index][2] ||
206
             quatIndex== mBadCornerQuats[index][3]  );
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210
// TYPE 1
211

    
212
  private boolean isPermittedDo(int angle)
213
    {
214
    if( mQuatMult==null ) initializeQuatMult();
215

    
216
    for(int corner=0; corner<8; corner++)
217
      {
218
      if( !cornerIsUp(corner) )
219
        {
220
        int currQuat = mCornerQuat[corner];
221
        int finalQuat= mQuatMult[angle][currQuat];
222
        if( quatIsBad(finalQuat,corner) ) return false;
223
        }
224
      }
225

    
226
    return true;
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230
// TYPE 1
231

    
232
  private boolean isPermittedUp(int angle)
233
    {
234
    if( mQuatMult==null ) initializeQuatMult();
235

    
236
    for(int corner=0; corner<8; corner++)
237
      {
238
      if( cornerIsUp(corner) )
239
        {
240
        int currQuat = mCornerQuat[corner];
241
        int finalQuat= mQuatMult[angle][currQuat];
242
        if( quatIsBad(finalQuat,corner) ) return false;
243
        }
244
      }
245

    
246
    return true;
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250
// TYPE 1
251

    
252
  private void computePermittedAngles()
253
    {
254
    mPermittedDo = 0;
255

    
256
    for(int angle=0; angle<BASIC_ANGLE; angle++)
257
      {
258
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
259
      }
260

    
261
    mPermittedUp = 0;
262

    
263
    for(int angle=0; angle<BASIC_ANGLE; angle++)
264
      {
265
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
266
      }
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270
// TYPE 1
271

    
272
  private int getNextAngle(Random rnd, int layer)
273
    {
274
    int num = layer==0 ? mPermittedDo:mPermittedUp;
275
    int index = rnd.nextInt(num);
276
    int angle = mPermittedAngles[layer][index];
277
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281
// TYPE 1
282

    
283
  private int getNextAngleNotZero(Random rnd, int layer)
284
    {
285
    int num = layer==0 ? mPermittedDo:mPermittedUp;
286
    int index = rnd.nextInt(num-1);
287
    int angle = mPermittedAngles[layer][index+1];
288
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
289
    }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292
// TYPE 1
293

    
294
  private int makeQuat(int axis,int index)
295
    {
296
    if( axis==1 ) return 13;
297
    if( index<0 ) index+=12;
298
    return index;
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302
// TYPE 1
303

    
304
  private boolean cornerBelongs(int index, int axis, int layer)
305
    {
306
    if( axis==0 )
307
      {
308
      boolean up = cornerIsUp(index);
309
      return ((up && layer==2) || (!up && layer==0));
310
      }
311
    else
312
      {
313
      boolean le = cornerIsLeft(index);
314
      return ((le && layer==0) || (!le && layer==1));
315
      }
316
    }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319
// TYPE 1
320

    
321
  private void updateCornerQuats(int[] rotInfo)
322
    {
323
    if( mQuatMult==null ) initializeQuatMult();
324

    
325
    int axis = rotInfo[0];
326
    int layer= rotInfo[1];
327
    int index=-rotInfo[2];
328

    
329
    int quat = makeQuat(axis,index);
330

    
331
    for(int corner=0; corner<8; corner++)
332
      {
333
      if( cornerBelongs(corner,axis,layer) )
334
        {
335
        int curr = mCornerQuat[corner];
336
        mCornerQuat[corner] = mQuatMult[quat][curr];
337
        }
338
      }
339
    }
340

    
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342
// TYPE 1
343

    
344
  private void randomizeNewScramble1(int[][] scramble, Random rnd, int curr, int total)
345
    {
346
    int layer, nextAngle;
347

    
348
    if( curr==0 )
349
      {
350
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
351
      mLastRot = rnd.nextInt(4);
352
      computePermittedAngles();
353
      }
354

    
355
    switch(mLastRot)
356
      {
357
      case LAST_SL: layer = rnd.nextInt(2);
358
                    nextAngle = getNextAngle(rnd,layer);
359

    
360
                    if( nextAngle==0 )
361
                      {
362
                      layer = 1-layer;
363
                      nextAngle = getNextAngleNotZero(rnd,layer);
364
                      }
365

    
366
                    scramble[curr][0] = 0;
367
                    scramble[curr][1] = 2*layer;
368
                    scramble[curr][2] = nextAngle;
369
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
370
                    updateCornerQuats(scramble[curr]);
371
                    break;
372
      case LAST_LO:
373
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
374
                    nextAngle = getNextAngle(rnd,layer);
375

    
376
                    if( nextAngle!=0 )
377
                      {
378
                      scramble[curr][0] = 0;
379
                      scramble[curr][1] = 2*layer;
380
                      scramble[curr][2] = nextAngle;
381
                      updateCornerQuats(scramble[curr]);
382
                      mLastRot = LAST_UL;
383
                      }
384
                    else
385
                      {
386
                      scramble[curr][0] = 1;
387
                      scramble[curr][1] = rnd.nextInt(2);
388
                      scramble[curr][2] = 1;
389
                      mLastRot = LAST_SL;
390
                      updateCornerQuats(scramble[curr]);
391
                      computePermittedAngles();
392
                      }
393

    
394
                    break;
395
      case LAST_UL: scramble[curr][0] = 1;
396
                    scramble[curr][1] = rnd.nextInt(2);
397
                    scramble[curr][2] = 1;
398
                    mLastRot = LAST_SL;
399
                    updateCornerQuats(scramble[curr]);
400
                    computePermittedAngles();
401
                    break;
402
      }
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// PUBLIC API
407

    
408
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
409
    {
410
    if( mType==0 ) randomizeNewScramble0(scramble, rnd, curr, total);
411
    if( mType==1 ) randomizeNewScramble1(scramble, rnd, curr, total);
412
    }
413
  }
(15-15/15)