Project

General

Profile

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

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

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.FactoryCubit;
25
import org.distorted.helpers.ObjectShape;
26
import org.distorted.helpers.ObjectSticker;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
class TwistySquare1 extends TwistySquare
41
{
42
  private static final int[] QUAT_NUMBER = new int[]
43
    {
44
      0, 6,
45
      0, 9, 6, 3, 18, 15, 12, 21,
46
      0, 9, 6, 3, 15, 12, 21, 18
47
    };
48

    
49
  // centers of the 2 middles + 8 edges + 8 corners
50
  private static final float[][] CENTERS = new float[][]
51
    {
52
      { 1.5f, 0.0f, 0.0f },
53
      {-1.5f, 0.0f, 0.0f },
54

    
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
      { 0.0f,-1.0f, 1.5f },
60
      { 1.5f,-1.0f, 0.0f },
61
      { 0.0f,-1.0f,-1.5f },
62
      {-1.5f,-1.0f, 0.0f },
63

    
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
      { 1.0f,-1.0f, 2.0f, 2.0f,-1.0f, 1.0f },
69
      { 1.0f,-1.0f,-2.0f, 2.0f,-1.0f,-1.0f },
70
      {-1.0f,-1.0f,-2.0f,-2.0f,-1.0f,-1.0f },
71
      {-1.0f,-1.0f, 2.0f,-2.0f,-1.0f, 1.0f }
72
    };
73

    
74
  private static final double[][] VERTICES_CORNER = new double[][]
75
    {
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
      { X-1.5,-0.5,  0.0 },
81
      {   0.0,-0.5,  0.0 },
82
      {   0.0,-0.5,X-1.5 },
83
      {  -1.5,-0.5, -1.5 }
84
    };
85

    
86
  private static final int[][] VERT_INDEXES_CORNER = new int[][]
87
    {
88
      {0,1,2,3},   // counterclockwise!
89
      {4,5,6,7},
90
      {4,5,1,0},
91
      {5,6,2,1},
92
      {7,4,0,3},
93
      {6,7,3,2}
94
    };
95

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

    
106
  private static final int NUM_STICKERS = STICKERS.length;
107

    
108
  private static final int[][] mStickerType = new int[][]
109
    {
110
      {  NUM_STICKERS,NUM_STICKERS,0,           1,           2,NUM_STICKERS },
111
      {             3,NUM_STICKERS,4,NUM_STICKERS,NUM_STICKERS,NUM_STICKERS },
112
      {             5,NUM_STICKERS,2,           2,NUM_STICKERS,NUM_STICKERS }
113
    };
114

    
115
  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4 ORANGE 5
116
  private static final int[][] mStickerColor = new int[][]
117
    {
118
      { 0, 0, 4, 0, 5, 0 },
119
      { 0, 0, 5, 1, 4, 0 },
120

    
121
      { 2, 0, 4, 0, 0, 0 },
122
      { 2, 0, 0, 0, 0, 0 },
123
      { 2, 0, 5, 0, 0, 0 },
124
      { 2, 0, 1, 0, 0, 0 },
125
      { 3, 0, 4, 0, 0, 0 },
126
      { 3, 0, 0, 0, 0, 0 },
127
      { 3, 0, 5, 0, 0, 0 },
128
      { 3, 0, 1, 0, 0, 0 },
129

    
130
      { 2, 0, 4, 0, 0, 0 },
131
      { 2, 0, 0, 5, 0, 0 },
132
      { 2, 0, 5, 1, 0, 0 },
133
      { 2, 0, 1, 4, 0, 0 },
134
      { 3, 0, 0, 4, 0, 0 },
135
      { 3, 0, 5, 0, 0, 0 },
136
      { 3, 0, 1, 5, 0, 0 },
137
      { 3, 0, 4, 1, 0, 0 },
138
    };
139

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

    
147
  private final int[][] mPermittedAngles;
148
  private final int[] mCornerQuat;
149
  private int mPermittedUp, mPermittedDo;
150

    
151
  private static final ObjectSticker[] mStickers;
152

    
153
  static
154
    {
155
    mStickers = new ObjectSticker[NUM_STICKERS];
156
    final float R1 = 0.06f;
157
    final float R2 = 0.04f;
158
    final float R3 = 0.11f;
159
    final float R4 = 0.03f;
160
    final float R5 = 0.11f;
161
    final float R6 = 0.08f;
162
    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} };
163
    final float[] strokes = { 0.05f,0.04f,0.09f,0.05f,0.08f,0.08f };
164

    
165
    for(int s=0; s<NUM_STICKERS; s++)
166
      {
167
      mStickers[s] = new ObjectSticker(STICKERS[s],null,radii[s],strokes[s]);
168
      }
169
    }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
  TwistySquare1(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
174
                DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
175
    {
176
    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU1, res, scrWidth);
177

    
178
    mLastRot = LAST_SL;
179
    mPermittedAngles = new int[2][BASIC_ANGLE[0]];
180
    mCornerQuat = new int[8];
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  ObjectShape getObjectShape(int cubit, int numLayers)
186
    {
187
    int variant = getCubitVariant(cubit,numLayers);
188

    
189
    if( variant==0 )
190
      {
191
      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} };
192
      int[] bandIndices   = new int[] { 2,2,1,1,0,2 };
193
      float[][] corners   = new float[][] { {0.03f,0.05f} };
194
      int[] cornerIndices = new int[] { 0,0,0,0,0,0,0,0 };
195
      float[][] centers   = new float[][] { { -0.75f, 0.0f, 0.0f} };
196
      int[] centerIndices = new int[] { 0,0,0,0,0,0,0,0 };
197

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

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

    
220
      return new ObjectShape(VERTICES_CORNER,VERT_INDEXES_CORNER,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
221
      }
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
  private Static4D getQuat(int cubit, int numLayers)
227
    {
228
    return QUATS[QUAT_NUMBER[cubit]];
229
    }
230

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

    
233
  private int getNumCubitVariants(int numLayers)
234
    {
235
    return 3;
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
  int getCubitVariant(int cubit, int numLayers)
241
    {
242
    return cubit<2 ? 0 : (cubit<10 ? 1:2);
243
    }
244

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

    
247
  MeshBase createCubitMesh(int cubit, int numLayers)
248
    {
249
    int variant = getCubitVariant(cubit,numLayers);
250

    
251
    if( mMeshes==null )
252
      {
253
      FactoryCubit factory = FactoryCubit.getInstance();
254
      factory.clear();
255
      mMeshes = new MeshBase[getNumCubitVariants(numLayers)];
256
      }
257

    
258
    if( mMeshes[variant]==null )
259
      {
260
      ObjectShape shape = getObjectShape(cubit,numLayers);
261
      FactoryCubit factory = FactoryCubit.getInstance();
262
      factory.createNewFaceTransform(shape);
263
      mMeshes[variant] = factory.createRoundedSolid(shape);
264
      }
265

    
266
    MeshBase mesh = mMeshes[variant].copy(true);
267
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
268
    mesh.apply(quat,0xffffffff,0);
269

    
270
    return mesh;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  ObjectSticker retSticker(int face)
276
    {
277
    return mStickers[face/NUM_FACES];
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  float[][] getCubitPositions(int numLayers)
283
    {
284
    return CENTERS;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  int getNumStickerTypes(int numLayers)
290
    {
291
    return NUM_STICKERS;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  int getFaceColor(int cubit, int cubitface, int numLayers)
297
    {
298
    int variant = getCubitVariant(cubit,numLayers);
299
    return mStickerType[variant][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
300
    }
301

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

    
306
  int computeBitmapFromRow(int rowBitmap, int axis)
307
    {
308
    int bitmap, initBitmap=0;
309

    
310
    while( initBitmap!=rowBitmap )
311
      {
312
      initBitmap = rowBitmap;
313

    
314
      for(int cubit=0; cubit<NUM_CUBITS; cubit++)
315
        {
316
        bitmap = CUBITS[cubit].mRotationRow[axis];
317
        if( (rowBitmap & bitmap) != 0 ) rowBitmap |= bitmap;
318
        }
319
      }
320

    
321
    return rowBitmap;
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
  private boolean cornerIsUp(int index)
327
    {
328
    return ((index<4) ^ (mCornerQuat[index]>=12));
329
    }
330

    
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332

    
333
  private boolean cornerIsLeft(int index)
334
    {
335
    int q = mCornerQuat[index];
336

    
337
    switch(index)
338
      {
339
      case 0:
340
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
341
      case 1:
342
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
343
      case 2:
344
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
345
      case 3:
346
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
347
      }
348

    
349
    return false;
350
    }
351

    
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353

    
354
  private boolean quatIsBad(int quatIndex, int corner)
355
    {
356
    int index = (corner%2);
357

    
358
    return ( quatIndex==BAD_CORNER_QUATS[index][0] ||
359
             quatIndex==BAD_CORNER_QUATS[index][1] ||
360
             quatIndex==BAD_CORNER_QUATS[index][2] ||
361
             quatIndex==BAD_CORNER_QUATS[index][3]  );
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  private boolean isPermittedDo(int angle)
367
    {
368
    for(int corner=0; corner<8; corner++)
369
      {
370
      if( !cornerIsUp(corner) )
371
        {
372
        int currQuat = mCornerQuat[corner];
373
        int finalQuat= QUAT_MULT[angle][currQuat];
374
        if( quatIsBad(finalQuat,corner) ) return false;
375
        }
376
      }
377

    
378
    return true;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
  private boolean isPermittedUp(int angle)
384
    {
385
    for(int corner=0; corner<8; corner++)
386
      {
387
      if( cornerIsUp(corner) )
388
        {
389
        int currQuat = mCornerQuat[corner];
390
        int finalQuat= QUAT_MULT[angle][currQuat];
391
        if( quatIsBad(finalQuat,corner) ) return false;
392
        }
393
      }
394

    
395
    return true;
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399

    
400
  private void computePermittedAngles()
401
    {
402
    mPermittedDo = 0;
403

    
404
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
405
      {
406
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
407
      }
408

    
409
    mPermittedUp = 0;
410

    
411
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
412
      {
413
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
414
      }
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  private int getNextAngle(Random rnd, int layer)
420
    {
421
    int basic = BASIC_ANGLE[0];
422
    int num = layer==0 ? mPermittedDo:mPermittedUp;
423
    int index = rnd.nextInt(num);
424
    int angle = mPermittedAngles[layer][index];
425
    return angle<basic/2 ? -angle : basic-angle;
426
    }
427

    
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429

    
430
  private int getNextAngleNotZero(Random rnd, int layer)
431
    {
432
    int basic = BASIC_ANGLE[0];
433
    int num = layer==0 ? mPermittedDo:mPermittedUp;
434
    int index = rnd.nextInt(num-1);
435
    int angle = mPermittedAngles[layer][index+1];
436
    return angle<basic/2 ? -angle : basic-angle;
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  private int makeQuat(int axis,int index)
442
    {
443
    if( axis==1 ) return 13;
444
    if( index<0 ) index+=12;
445
    return index;
446
    }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

    
450
  private boolean cornerBelongs(int index, int axis, int layer)
451
    {
452
    if( axis==0 )
453
      {
454
      boolean up = cornerIsUp(index);
455
      return ((up && layer==2) || (!up && layer==0));
456
      }
457
    else
458
      {
459
      boolean le = cornerIsLeft(index);
460
      return ((le && layer==0) || (!le && layer==1));
461
      }
462
    }
463

    
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465

    
466
  private void updateCornerQuats(int[] rotInfo)
467
    {
468
    int axis = rotInfo[0];
469
    int layer= rotInfo[1];
470
    int index=-rotInfo[2];
471

    
472
    int quat = makeQuat(axis,index);
473

    
474
    for(int corner=0; corner<8; corner++)
475
      {
476
      if( cornerBelongs(corner,axis,layer) )
477
        {
478
        int curr = mCornerQuat[corner];
479
        mCornerQuat[corner] = QUAT_MULT[quat][curr];
480
        }
481
      }
482
    }
483

    
484
///////////////////////////////////////////////////////////////////////////////////////////////////
485
// PUBLIC API
486

    
487
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
488
    {
489
    int layer, nextAngle;
490

    
491
    if( curr==0 )
492
      {
493
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
494
      mLastRot = rnd.nextInt(4);
495
      computePermittedAngles();
496
      }
497

    
498
    switch(mLastRot)
499
      {
500
      case LAST_SL: layer = rnd.nextInt(2);
501
                    nextAngle = getNextAngle(rnd,layer);
502

    
503
                    if( nextAngle==0 )
504
                      {
505
                      layer = 1-layer;
506
                      nextAngle = getNextAngleNotZero(rnd,layer);
507
                      }
508

    
509
                    scramble[curr][0] = 0;
510
                    scramble[curr][1] = 2*layer;
511
                    scramble[curr][2] = nextAngle;
512
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
513
                    updateCornerQuats(scramble[curr]);
514
                    break;
515
      case LAST_LO:
516
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
517
                    nextAngle = getNextAngle(rnd,layer);
518

    
519
                    if( nextAngle!=0 )
520
                      {
521
                      scramble[curr][0] = 0;
522
                      scramble[curr][1] = 2*layer;
523
                      scramble[curr][2] = nextAngle;
524
                      updateCornerQuats(scramble[curr]);
525
                      mLastRot = LAST_UL;
526
                      }
527
                    else
528
                      {
529
                      scramble[curr][0] = 1;
530
                      scramble[curr][1] = rnd.nextInt(2);
531
                      scramble[curr][2] = 1;
532
                      mLastRot = LAST_SL;
533
                      updateCornerQuats(scramble[curr]);
534
                      computePermittedAngles();
535
                      }
536

    
537
                    break;
538
      case LAST_UL: scramble[curr][0] = 1;
539
                    scramble[curr][1] = rnd.nextInt(2);
540
                    scramble[curr][2] = 1;
541
                    mLastRot = LAST_SL;
542
                    updateCornerQuats(scramble[curr]);
543
                    computePermittedAngles();
544
                    break;
545
      }
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  public boolean isSolved()
551
    {
552
    int index = CUBITS[0].mQuatIndex;
553

    
554
    for(int i=1; i<NUM_CUBITS; i++)
555
      {
556
      if( CUBITS[i].mQuatIndex != index ) return false;
557
      }
558

    
559
    return true;
560
    }
561

    
562
///////////////////////////////////////////////////////////////////////////////////////////////////
563

    
564
  public int getObjectName(int numLayers)
565
    {
566
    return R.string.squa1;
567
    }
568

    
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570

    
571
  public int getInventor(int numLayers)
572
    {
573
    return R.string.squa1_inventor;
574
    }
575

    
576
///////////////////////////////////////////////////////////////////////////////////////////////////
577

    
578
  public int getComplexity(int numLayers)
579
    {
580
    return 9;
581
    }
582
}
(39-39/41)