Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / scrambling / ObjectScrambler.java @ 2addda73

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

    
22
import java.util.Random;
23

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

    
26
public class ObjectScrambler
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
  public ObjectScrambler(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

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

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

    
88
      mNumOccurences = new int[max];
89
      }
90

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

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
// PUBLIC API
101

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

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

    
113
    scramble[curr][0] = info[0];
114
    scramble[curr][1] = info[1];
115
    scramble[curr][2] = info[2];
116

    
117
    mCurrState     = info[3];
118
    mIndexExcluded = info[0];
119
    }
120

    
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122
// TYPE 1
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

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

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159
// TYPE 1
160

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

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167
// TYPE 1
168

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

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

    
185
    return false;
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
// TYPE 1
190

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

    
199
    int index = (corner%2);
200

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

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208
// TYPE 1
209

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

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

    
224
    return true;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
// TYPE 1
229

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

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

    
244
    return true;
245
    }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248
// TYPE 1
249

    
250
  private void computePermittedAngles()
251
    {
252
    mPermittedDo = 0;
253

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

    
259
    mPermittedUp = 0;
260

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

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268
// TYPE 1
269

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

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279
// TYPE 1
280

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

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
// TYPE 1
291

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

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300
// TYPE 1
301

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

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317
// TYPE 1
318

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

    
323
    int axis = rotInfo[0];
324
    int layer= rotInfo[1];
325
    int index=-rotInfo[2];
326

    
327
    int quat = makeQuat(axis,index);
328

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

    
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340
// TYPE 1
341

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

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

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

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

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

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

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

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404
// PUBLIC API
405

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