Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistySquare1.java @ abe288a3

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

    
22
import android.content.res.Resources;
23

    
24
import org.distorted.helpers.ObjectShape;
25
import org.distorted.helpers.ObjectSticker;
26
import org.distorted.library.main.DistortedEffects;
27
import org.distorted.library.main.DistortedTexture;
28
import org.distorted.library.mesh.MeshSquare;
29
import org.distorted.library.type.Static4D;
30
import org.distorted.main.R;
31

    
32
import java.util.Random;
33

    
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35

    
36
class TwistySquare1 extends TwistySquare
37
{
38
  private static final int[] QUAT_NUMBER = new int[]
39
    {
40
      0, 6,
41
      0, 9, 6, 3, 18, 15, 12, 21,
42
      0, 9, 6, 3, 15, 12, 21, 18
43
    };
44

    
45
  // centers of the 2 middles + 8 edges + 8 corners
46
  private static final float[][] CENTERS = new float[][]
47
    {
48
      { 1.5f, 0.0f, 0.0f },
49
      {-1.5f, 0.0f, 0.0f },
50

    
51
      { 0.0f, 1.0f, 1.5f },
52
      { 1.5f, 1.0f, 0.0f },
53
      { 0.0f, 1.0f,-1.5f },
54
      {-1.5f, 1.0f, 0.0f },
55
      { 0.0f,-1.0f, 1.5f },
56
      { 1.5f,-1.0f, 0.0f },
57
      { 0.0f,-1.0f,-1.5f },
58
      {-1.5f,-1.0f, 0.0f },
59

    
60
      { 1.0f, 1.0f, 2.0f, 2.0f, 1.0f, 1.0f },
61
      { 1.0f, 1.0f,-2.0f, 2.0f, 1.0f,-1.0f },
62
      {-1.0f, 1.0f,-2.0f,-2.0f, 1.0f,-1.0f },
63
      {-1.0f, 1.0f, 2.0f,-2.0f, 1.0f, 1.0f },
64
      { 1.0f,-1.0f, 2.0f, 2.0f,-1.0f, 1.0f },
65
      { 1.0f,-1.0f,-2.0f, 2.0f,-1.0f,-1.0f },
66
      {-1.0f,-1.0f,-2.0f,-2.0f,-1.0f,-1.0f },
67
      {-1.0f,-1.0f, 2.0f,-2.0f,-1.0f, 1.0f }
68
    };
69

    
70
  private static final double[][] VERTICES_CORNER = new double[][]
71
    {
72
      { X-1.5, 0.5,  0.0 },
73
      {   0.0, 0.5,  0.0 },
74
      {   0.0, 0.5,X-1.5 },
75
      {  -1.5, 0.5, -1.5 },
76
      { X-1.5,-0.5,  0.0 },
77
      {   0.0,-0.5,  0.0 },
78
      {   0.0,-0.5,X-1.5 },
79
      {  -1.5,-0.5, -1.5 }
80
    };
81

    
82
  private static final int[][] VERT_INDEXES_CORNER = new int[][]
83
    {
84
      {0,1,2,3},   // counterclockwise!
85
      {4,5,6,7},
86
      {4,5,1,0},
87
      {5,6,2,1},
88
      {7,4,0,3},
89
      {6,7,3,2}
90
    };
91

    
92
  private static final float[][] STICKERS = new float[][]
93
    {
94
      { -0.5f, -0.26289170f, 0.5f, -0.26289170f, 0.5f, 0.26289170f, -0.5f, 0.26289170f }, // middle front
95
      { -0.5f, -0.16666667f, 0.5f, -0.16666667f, 0.5f, 0.16666667f, -0.5f, 0.16666667f }, // middle right
96
      { -0.5f, -0.45534182f, 0.5f, -0.45534182f, 0.5f, 0.45534182f, -0.5f, 0.45534182f }, // middle back
97
      { -0.20096192f, -0.25f, 0.20096192f, -0.25f, 0.0f, 0.5f },                          // edge top
98
      { -0.40192384f, -0.5f, 0.40192384f, -0.5f, 0.40192384f, 0.5f, -0.40192384f, 0.5f }, // edge face
99
      { -0.2637079f, -0.38185397f, 0.38185397f, -0.38185397f, 0.38185397f, 0.2637079f, -0.5f, 0.5f } // corner top
100
    };
101

    
102
  private static final int NUM_STICKERS = STICKERS.length;
103

    
104
  private static final int[][] mStickerType = new int[][]
105
    {
106
      {  NUM_STICKERS,NUM_STICKERS,0,           1,           2,NUM_STICKERS },
107
      {             3,NUM_STICKERS,4,NUM_STICKERS,NUM_STICKERS,NUM_STICKERS },
108
      {             5,NUM_STICKERS,2,           2,NUM_STICKERS,NUM_STICKERS }
109
    };
110

    
111
  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4 ORANGE 5
112
  private static final int[][] mStickerColor = new int[][]
113
    {
114
      { 0, 0, 4, 0, 5, 0 },
115
      { 0, 0, 5, 1, 4, 0 },
116

    
117
      { 2, 0, 4, 0, 0, 0 },
118
      { 2, 0, 0, 0, 0, 0 },
119
      { 2, 0, 5, 0, 0, 0 },
120
      { 2, 0, 1, 0, 0, 0 },
121
      { 3, 0, 4, 0, 0, 0 },
122
      { 3, 0, 0, 0, 0, 0 },
123
      { 3, 0, 5, 0, 0, 0 },
124
      { 3, 0, 1, 0, 0, 0 },
125

    
126
      { 2, 0, 4, 0, 0, 0 },
127
      { 2, 0, 0, 5, 0, 0 },
128
      { 2, 0, 5, 1, 0, 0 },
129
      { 2, 0, 1, 4, 0, 0 },
130
      { 3, 0, 0, 4, 0, 0 },
131
      { 3, 0, 5, 0, 0, 0 },
132
      { 3, 0, 1, 5, 0, 0 },
133
      { 3, 0, 4, 1, 0, 0 },
134
    };
135

    
136
  // quat indices that make corner cubits bandage the puzzle.
137
  private static final int[][] BAD_CORNER_QUATS = new int[][]
138
    {
139
      { 2, 8,17,23},
140
      { 5,11,14,20},
141
    };
142

    
143
  private final int[][] mPermittedAngles;
144
  private final int[] mCornerQuat;
145
  private int mPermittedUp, mPermittedDo;
146

    
147
  private static final ObjectSticker[] mStickers;
148

    
149
  static
150
    {
151
    mStickers = new ObjectSticker[NUM_STICKERS];
152
    final float R1 = 0.06f;
153
    final float R2 = 0.04f;
154
    final float R3 = 0.11f;
155
    final float R4 = 0.03f;
156
    final float R5 = 0.11f;
157
    final float R6 = 0.08f;
158
    final float[][] radii  = { {R1,R1,R1,R1},{R2,R2,R2,R2},{R3,R3,R3,R3},{R4,R4,R4},{R5,R5,R5,R5},{R6,R6,R6,R6} };
159
    final float[] strokes = { 0.05f,0.04f,0.09f,0.05f,0.08f,0.08f };
160

    
161
    for(int s=0; s<NUM_STICKERS; s++)
162
      {
163
      mStickers[s] = new ObjectSticker(STICKERS[s],null,radii[s],strokes[s]);
164
      }
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
  TwistySquare1(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
170
                DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
171
    {
172
    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU1, res, scrWidth);
173

    
174
    mLastRot = LAST_SL;
175
    mPermittedAngles = new int[2][BASIC_ANGLE[0]];
176
    mCornerQuat = new int[8];
177
    }
178

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

    
181
  ObjectShape getObjectShape(int cubit, int numLayers)
182
    {
183
    int variant = getCubitVariant(cubit,numLayers);
184

    
185
    if( variant==0 )
186
      {
187
      float[][] bands     = new float[][] { {0.040f,35,0.8f,1.0f,5,2,1}, {0.020f,35,0.8f,1.0f,5,2,1}, {0.001f,35,0.8f,1.0f,5,2,1} };
188
      int[] bandIndices   = new int[] { 2,2,1,1,0,2 };
189
      float[][] corners   = new float[][] { {0.03f,0.05f} };
190
      int[] cornerIndices = new int[] { 0,0,0,0,0,0,0,0 };
191
      float[][] centers   = new float[][] { { -0.75f, 0.0f, 0.0f} };
192
      int[] centerIndices = new int[] { 0,0,0,0,0,0,0,0 };
193

    
194
      return new ObjectShape(VERTICES_MIDDLE,VERT_INDEXES_MIDDLE,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
195
      }
196
    else if( variant==1 )
197
      {
198
      float[][] bands     = new float[][] { {0.038f,35,0.5f,0.9f, 5,2,1}, {0.001f,35,0.5f,0.9f, 5,2,1} };
199
      int[] bandIndices   = new int[] { 0,1,0,1,1 };
200
      float[][] corners   = new float[][] { {0.04f,0.15f} };
201
      int[] cornerIndices = new int[] { 0,0,-1,0,0,-1 };
202
      float[][] centers   = new float[][] { { 0.0f, 0.0f,-0.5f} };
203
      int[] centerIndices = new int[] { 0,0,-1,0,0,-1 };
204

    
205
      return new ObjectShape(VERTICES_EDGE,VERT_INDEXES_EDGE,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
206
      }
207
    else
208
      {
209
      float[][] bands     = new float[][] { {0.038f,35,0.9f,1.0f, 5,2,1}, {0.001f,35,0.9f,1.0f, 5,2,1} };
210
      int[] bandIndices   = new int[] { 0,1,0,0,1,1 };
211
      float[][] corners   = new float[][] { {0.05f,0.13f} };
212
      int[] cornerIndices = new int[] { 0,0,0,-1,0,0,0,-1 };
213
      float[][] centers   = new float[][] { { -0.5f, 0.0f,-0.5f} };
214
      int[] centerIndices = new int[] { -1,0,-1,-1,-1,0,-1,-1 };
215

    
216
      return new ObjectShape(VERTICES_CORNER,VERT_INDEXES_CORNER,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
217
      }
218
    }
219

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

    
222
  Static4D getQuat(int cubit, int numLayers)
223
    {
224
    return QUATS[QUAT_NUMBER[cubit]];
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  int getNumCubitVariants(int numLayers)
230
    {
231
    return 3;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  int getCubitVariant(int cubit, int numLayers)
237
    {
238
    return cubit<2 ? 0 : (cubit<10 ? 1:2);
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  ObjectSticker retSticker(int face)
244
    {
245
    return mStickers[face/NUM_FACES];
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  float[][] getCubitPositions(int numLayers)
251
    {
252
    return CENTERS;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  int getNumStickerTypes(int numLayers)
258
    {
259
    return NUM_STICKERS;
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
  int getFaceColor(int cubit, int cubitface, int numLayers)
265
    {
266
    int variant = getCubitVariant(cubit,numLayers);
267
    return mStickerType[variant][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
// this implements the fact that corner cubits have multiple 'centers' and this means the cubit
272
// might span more than one layer along a given axis - i.e. that this is a bandaged puzzle.
273

    
274
  int computeBitmapFromRow(int rowBitmap, int axis)
275
    {
276
    int bitmap, initBitmap=0;
277

    
278
    while( initBitmap!=rowBitmap )
279
      {
280
      initBitmap = rowBitmap;
281

    
282
      for(int cubit=0; cubit<NUM_CUBITS; cubit++)
283
        {
284
        bitmap = CUBITS[cubit].mRotationRow[axis];
285
        if( (rowBitmap & bitmap) != 0 ) rowBitmap |= bitmap;
286
        }
287
      }
288

    
289
    return rowBitmap;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  private boolean cornerIsUp(int index)
295
    {
296
    return ((index<4) ^ (mCornerQuat[index]>=12));
297
    }
298

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

    
301
  private boolean cornerIsLeft(int index)
302
    {
303
    int q = mCornerQuat[index];
304

    
305
    switch(index)
306
      {
307
      case 0:
308
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
309
      case 1:
310
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
311
      case 2:
312
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
313
      case 3:
314
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
315
      }
316

    
317
    return false;
318
    }
319

    
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

    
322
  private boolean quatIsBad(int quatIndex, int corner)
323
    {
324
    int index = (corner%2);
325

    
326
    return ( quatIndex==BAD_CORNER_QUATS[index][0] ||
327
             quatIndex==BAD_CORNER_QUATS[index][1] ||
328
             quatIndex==BAD_CORNER_QUATS[index][2] ||
329
             quatIndex==BAD_CORNER_QUATS[index][3]  );
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
  private boolean isPermittedDo(int angle)
335
    {
336
    for(int corner=0; corner<8; corner++)
337
      {
338
      if( !cornerIsUp(corner) )
339
        {
340
        int currQuat = mCornerQuat[corner];
341
        int finalQuat= QUAT_MULT[angle][currQuat];
342
        if( quatIsBad(finalQuat,corner) ) return false;
343
        }
344
      }
345

    
346
    return true;
347
    }
348

    
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350

    
351
  private boolean isPermittedUp(int angle)
352
    {
353
    for(int corner=0; corner<8; corner++)
354
      {
355
      if( cornerIsUp(corner) )
356
        {
357
        int currQuat = mCornerQuat[corner];
358
        int finalQuat= QUAT_MULT[angle][currQuat];
359
        if( quatIsBad(finalQuat,corner) ) return false;
360
        }
361
      }
362

    
363
    return true;
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367

    
368
  private void computePermittedAngles()
369
    {
370
    mPermittedDo = 0;
371

    
372
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
373
      {
374
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
375
      }
376

    
377
    mPermittedUp = 0;
378

    
379
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
380
      {
381
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
382
      }
383
    }
384

    
385
///////////////////////////////////////////////////////////////////////////////////////////////////
386

    
387
  private int getNextAngle(Random rnd, int layer)
388
    {
389
    int basic = BASIC_ANGLE[0];
390
    int num = layer==0 ? mPermittedDo:mPermittedUp;
391
    int index = rnd.nextInt(num);
392
    int angle = mPermittedAngles[layer][index];
393
    return angle<basic/2 ? -angle : basic-angle;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  private int getNextAngleNotZero(Random rnd, int layer)
399
    {
400
    int basic = BASIC_ANGLE[0];
401
    int num = layer==0 ? mPermittedDo:mPermittedUp;
402
    int index = rnd.nextInt(num-1);
403
    int angle = mPermittedAngles[layer][index+1];
404
    return angle<basic/2 ? -angle : basic-angle;
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408

    
409
  private int makeQuat(int axis,int index)
410
    {
411
    if( axis==1 ) return 13;
412
    if( index<0 ) index+=12;
413
    return index;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  private boolean cornerBelongs(int index, int axis, int layer)
419
    {
420
    if( axis==0 )
421
      {
422
      boolean up = cornerIsUp(index);
423
      return ((up && layer==2) || (!up && layer==0));
424
      }
425
    else
426
      {
427
      boolean le = cornerIsLeft(index);
428
      return ((le && layer==0) || (!le && layer==1));
429
      }
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

    
434
  private void updateCornerQuats(int[] rotInfo)
435
    {
436
    int axis = rotInfo[0];
437
    int layer= rotInfo[1];
438
    int index=-rotInfo[2];
439

    
440
    int quat = makeQuat(axis,index);
441

    
442
    for(int corner=0; corner<8; corner++)
443
      {
444
      if( cornerBelongs(corner,axis,layer) )
445
        {
446
        int curr = mCornerQuat[corner];
447
        mCornerQuat[corner] = QUAT_MULT[quat][curr];
448
        }
449
      }
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
// PUBLIC API
454

    
455
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
456
    {
457
    int layer, nextAngle;
458

    
459
    if( curr==0 )
460
      {
461
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
462
      mLastRot = rnd.nextInt(4);
463
      computePermittedAngles();
464
      }
465

    
466
    switch(mLastRot)
467
      {
468
      case LAST_SL: layer = rnd.nextInt(2);
469
                    nextAngle = getNextAngle(rnd,layer);
470

    
471
                    if( nextAngle==0 )
472
                      {
473
                      layer = 1-layer;
474
                      nextAngle = getNextAngleNotZero(rnd,layer);
475
                      }
476

    
477
                    scramble[curr][0] = 0;
478
                    scramble[curr][1] = 2*layer;
479
                    scramble[curr][2] = nextAngle;
480
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
481
                    updateCornerQuats(scramble[curr]);
482
                    break;
483
      case LAST_LO:
484
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
485
                    nextAngle = getNextAngle(rnd,layer);
486

    
487
                    if( nextAngle!=0 )
488
                      {
489
                      scramble[curr][0] = 0;
490
                      scramble[curr][1] = 2*layer;
491
                      scramble[curr][2] = nextAngle;
492
                      updateCornerQuats(scramble[curr]);
493
                      mLastRot = LAST_UL;
494
                      }
495
                    else
496
                      {
497
                      scramble[curr][0] = 1;
498
                      scramble[curr][1] = rnd.nextInt(2);
499
                      scramble[curr][2] = 1;
500
                      mLastRot = LAST_SL;
501
                      updateCornerQuats(scramble[curr]);
502
                      computePermittedAngles();
503
                      }
504

    
505
                    break;
506
      case LAST_UL: scramble[curr][0] = 1;
507
                    scramble[curr][1] = rnd.nextInt(2);
508
                    scramble[curr][2] = 1;
509
                    mLastRot = LAST_SL;
510
                    updateCornerQuats(scramble[curr]);
511
                    computePermittedAngles();
512
                    break;
513
      }
514
    }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

    
518
  public boolean isSolved()
519
    {
520
    int index = CUBITS[0].mQuatIndex;
521

    
522
    for(int i=1; i<NUM_CUBITS; i++)
523
      {
524
      if( CUBITS[i].mQuatIndex != index ) return false;
525
      }
526

    
527
    return true;
528
    }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531

    
532
  public int getObjectName(int numLayers)
533
    {
534
    return R.string.squa1;
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538

    
539
  public int getInventor(int numLayers)
540
    {
541
    return R.string.squa1_inventor;
542
    }
543

    
544
///////////////////////////////////////////////////////////////////////////////////////////////////
545

    
546
  public int getComplexity(int numLayers)
547
    {
548
    return 9;
549
    }
550
}
(39-39/41)