Project

General

Profile

Download (14.4 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / objectlib / TwistyObjectScrambler.java @ 588ace55

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;
21

    
22
import java.util.Random;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25

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

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

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

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

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

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

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

    
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71
// QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
72

    
73
  void initializeQuatMult()
74
    {
75
    mQuatMult = new int[][]
76
      {
77
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
78
        {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
79
        {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
80
        {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
81
        {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
82
        {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
83
        {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
84
        {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
85
        {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
86
        {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
87
        { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
88
        { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
89
        { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
90
        { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
91
        { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
92
        { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
93
        { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
94
        { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
95
        { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
96
        { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
97
        { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
98
        { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
99
        { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
100
        { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
101
      };
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  private void initializeScrambling()
107
    {
108
    if( mScrambleTable ==null )
109
      {
110
      mScrambleTable = new int[mNumAxis][mNumLayers];
111
      }
112
    if( mNumOccurences ==null )
113
      {
114
      int max=0;
115

    
116
      for (ScrambleState mState : mStates)
117
        {
118
        int tmp = mState.getTotal(-1);
119
        if (max < tmp) max = tmp;
120
        }
121

    
122
      mNumOccurences = new int[max];
123
      }
124

    
125
    for(int i=0; i<mNumAxis; i++)
126
      for(int j=0; j<mNumLayers; j++) mScrambleTable[i][j] = 0;
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130
// PUBLIC API
131

    
132
  private void randomizeNewScramble0(int[][] scramble, Random rnd, int curr, int total)
133
    {
134
    if( curr==0 )
135
      {
136
      mCurrState     = 0;
137
      mIndexExcluded =-1;
138
      initializeScrambling();
139
      }
140

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

    
143
    scramble[curr][0] = info[0];
144
    scramble[curr][1] = info[1];
145
    scramble[curr][2] = info[2];
146

    
147
    mCurrState     = info[3];
148
    mIndexExcluded = info[0];
149
    }
150

    
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152

    
153
  private boolean cornerIsUp(int index)
154
    {
155
    return ((index<4) ^ (mCornerQuat[index]>=12));
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private boolean cornerIsLeft(int index)
161
    {
162
    int q = mCornerQuat[index];
163

    
164
    switch(index)
165
      {
166
      case 0:
167
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
168
      case 1:
169
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
170
      case 2:
171
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
172
      case 3:
173
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
174
      }
175

    
176
    return false;
177
    }
178

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

    
181
  private boolean quatIsBad(int quatIndex, int corner)
182
    {
183
    if( mBadCornerQuats ==null )
184
      {
185
      // quat indices that make corner cubits bandage the puzzle.
186
      mBadCornerQuats = new int[][] { { 2, 8,17,23}, { 5,11,14,20} };
187
      }
188

    
189
    int index = (corner%2);
190

    
191
    return ( quatIndex== mBadCornerQuats[index][0] ||
192
             quatIndex== mBadCornerQuats[index][1] ||
193
             quatIndex== mBadCornerQuats[index][2] ||
194
             quatIndex== mBadCornerQuats[index][3]  );
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198

    
199
  private boolean isPermittedDo(int angle)
200
    {
201
    if( mQuatMult==null ) initializeQuatMult();
202

    
203
    for(int corner=0; corner<8; corner++)
204
      {
205
      if( !cornerIsUp(corner) )
206
        {
207
        int currQuat = mCornerQuat[corner];
208
        int finalQuat= mQuatMult[angle][currQuat];
209
        if( quatIsBad(finalQuat,corner) ) return false;
210
        }
211
      }
212

    
213
    return true;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  private boolean isPermittedUp(int angle)
219
    {
220
    if( mQuatMult==null ) initializeQuatMult();
221

    
222
    for(int corner=0; corner<8; corner++)
223
      {
224
      if( cornerIsUp(corner) )
225
        {
226
        int currQuat = mCornerQuat[corner];
227
        int finalQuat= mQuatMult[angle][currQuat];
228
        if( quatIsBad(finalQuat,corner) ) return false;
229
        }
230
      }
231

    
232
    return true;
233
    }
234

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

    
237
  private void computePermittedAngles()
238
    {
239
    mPermittedDo = 0;
240

    
241
    for(int angle=0; angle<BASIC_ANGLE; angle++)
242
      {
243
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
244
      }
245

    
246
    mPermittedUp = 0;
247

    
248
    for(int angle=0; angle<BASIC_ANGLE; angle++)
249
      {
250
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
251
      }
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  private int getNextAngle(Random rnd, int layer)
257
    {
258
    int num = layer==0 ? mPermittedDo:mPermittedUp;
259
    int index = rnd.nextInt(num);
260
    int angle = mPermittedAngles[layer][index];
261
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
262
    }
263

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

    
266
  private int getNextAngleNotZero(Random rnd, int layer)
267
    {
268
    int num = layer==0 ? mPermittedDo:mPermittedUp;
269
    int index = rnd.nextInt(num-1);
270
    int angle = mPermittedAngles[layer][index+1];
271
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  private int makeQuat(int axis,int index)
277
    {
278
    if( axis==1 ) return 13;
279
    if( index<0 ) index+=12;
280
    return index;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  private boolean cornerBelongs(int index, int axis, int layer)
286
    {
287
    if( axis==0 )
288
      {
289
      boolean up = cornerIsUp(index);
290
      return ((up && layer==2) || (!up && layer==0));
291
      }
292
    else
293
      {
294
      boolean le = cornerIsLeft(index);
295
      return ((le && layer==0) || (!le && layer==1));
296
      }
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

    
301
  private void updateCornerQuats(int[] rotInfo)
302
    {
303
    if( mQuatMult==null ) initializeQuatMult();
304

    
305
    int axis = rotInfo[0];
306
    int layer= rotInfo[1];
307
    int index=-rotInfo[2];
308

    
309
    int quat = makeQuat(axis,index);
310

    
311
    for(int corner=0; corner<8; corner++)
312
      {
313
      if( cornerBelongs(corner,axis,layer) )
314
        {
315
        int curr = mCornerQuat[corner];
316
        mCornerQuat[corner] = mQuatMult[quat][curr];
317
        }
318
      }
319
    }
320

    
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322

    
323
  private void randomizeNewScramble1(int[][] scramble, Random rnd, int curr, int total)
324
    {
325
    int layer, nextAngle;
326

    
327
    if( curr==0 )
328
      {
329
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
330
      mLastRot = rnd.nextInt(4);
331
      computePermittedAngles();
332
      }
333

    
334
    switch(mLastRot)
335
      {
336
      case LAST_SL: layer = rnd.nextInt(2);
337
                    nextAngle = getNextAngle(rnd,layer);
338

    
339
                    if( nextAngle==0 )
340
                      {
341
                      layer = 1-layer;
342
                      nextAngle = getNextAngleNotZero(rnd,layer);
343
                      }
344

    
345
                    scramble[curr][0] = 0;
346
                    scramble[curr][1] = 2*layer;
347
                    scramble[curr][2] = nextAngle;
348
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
349
                    updateCornerQuats(scramble[curr]);
350
                    break;
351
      case LAST_LO:
352
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
353
                    nextAngle = getNextAngle(rnd,layer);
354

    
355
                    if( nextAngle!=0 )
356
                      {
357
                      scramble[curr][0] = 0;
358
                      scramble[curr][1] = 2*layer;
359
                      scramble[curr][2] = nextAngle;
360
                      updateCornerQuats(scramble[curr]);
361
                      mLastRot = LAST_UL;
362
                      }
363
                    else
364
                      {
365
                      scramble[curr][0] = 1;
366
                      scramble[curr][1] = rnd.nextInt(2);
367
                      scramble[curr][2] = 1;
368
                      mLastRot = LAST_SL;
369
                      updateCornerQuats(scramble[curr]);
370
                      computePermittedAngles();
371
                      }
372

    
373
                    break;
374
      case LAST_UL: scramble[curr][0] = 1;
375
                    scramble[curr][1] = rnd.nextInt(2);
376
                    scramble[curr][2] = 1;
377
                    mLastRot = LAST_SL;
378
                    updateCornerQuats(scramble[curr]);
379
                    computePermittedAngles();
380
                    break;
381
      }
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385
// PUBLIC API
386

    
387
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
388
    {
389
    if( mType==0 ) randomizeNewScramble0(scramble, rnd, curr, total);
390
    if( mType==1 ) randomizeNewScramble1(scramble, rnd, curr, total);
391
    }
392
  }
(21-21/21)