Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistySquare1.java @ 9c06394a

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

    
35
import java.util.Random;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

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

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

    
54
      { 0.0f, 1.0f, 1.5f },
55
      { 1.5f, 1.0f, 0.0f },
56
      { 0.0f, 1.0f,-1.5f },
57
      {-1.5f, 1.0f, 0.0f },
58
      { 0.0f,-1.0f, 1.5f },
59
      { 1.5f,-1.0f, 0.0f },
60
      { 0.0f,-1.0f,-1.5f },
61
      {-1.5f,-1.0f, 0.0f },
62

    
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
      { 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
    };
72

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

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

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

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

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

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

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

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

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

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

    
150
  private static final ObjectSticker[] mStickers;
151

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

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

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

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

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

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  private Static4D getQuat(int cubit)
185
    {
186
    return QUATS[QUAT_NUMBER[cubit]];
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  MeshBase createCornerCubitMesh()
192
    {
193
    if( mMeshes[2]==null )
194
      {
195
      float[][] bands= new float[][]
196
        {
197
          {0.038f,35,0.9f,1.0f, 5,2,1},
198
          {0.001f,35,0.9f,1.0f, 5,2,1}
199
        };
200
      int[] bandIndexes   = new int[] { 0,1,0,0,1,1 };
201
      float[][] corners   = new float[][] { {0.05f,0.13f} };
202
      int[] cornerIndexes = new int[] { 0,0,0,-1,0,0,0,-1 };
203
      float[][] centers   = new float[][] { { -0.5f, 0.0f,-0.5f} };
204
      int[] centerIndexes = new int[] { -1,0,-1,-1,-1,0,-1,-1 };
205

    
206
      FactoryCubit factory = FactoryCubit.getInstance();
207
      factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
208
      mMeshes[2] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
209
                                              bands, bandIndexes,
210
                                              corners, cornerIndexes,
211
                                              centers, centerIndexes,
212
                                              getNumCubitFaces() );
213
      }
214
    return mMeshes[2].copy(true);
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  MeshBase createCubitMesh(int cubit, int numLayers)
220
    {
221
    if( mMeshes==null )
222
      {
223
      FactoryCubit factory = FactoryCubit.getInstance();
224
      factory.clear();
225
      mMeshes = new MeshBase[4];
226
      }
227

    
228
    MeshBase mesh;
229

    
230
         if( cubit< 2 ) mesh = createMiddleCubitMesh();
231
    else if( cubit<10 ) mesh = createEdgeCubitMesh();
232
    else                mesh = createCornerCubitMesh();
233

    
234
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
235
    mesh.apply(quat,0xffffffff,0);
236

    
237
    return mesh;
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

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

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

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

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

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

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  int getFaceColor(int cubit, int cubitface, int numLayers)
264
    {
265
    int type;
266

    
267
         if( cubit< 2 ) type = 0;
268
    else if( cubit<10 ) type = 1;
269
    else                type = 2;
270

    
271
    return mStickerType[type][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
272
    }
273

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

    
278
  int computeBitmapFromRow(int rowBitmap, int axis)
279
    {
280
    int bitmap, initBitmap=0;
281

    
282
    while( initBitmap!=rowBitmap )
283
      {
284
      initBitmap = rowBitmap;
285

    
286
      for(int cubit=0; cubit<NUM_CUBITS; cubit++)
287
        {
288
        bitmap = CUBITS[cubit].mRotationRow[axis];
289
        if( (rowBitmap & bitmap) != 0 ) rowBitmap |= bitmap;
290
        }
291
      }
292

    
293
    return rowBitmap;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  private boolean cornerIsUp(int index)
299
    {
300
    return ((index<4) ^ (mCornerQuat[index]>=12));
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

    
305
  private boolean cornerIsLeft(int index)
306
    {
307
    int q = mCornerQuat[index];
308

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

    
321
    return false;
322
    }
323

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

    
326
  private boolean quatIsBad(int quatIndex, int corner)
327
    {
328
    int index = (corner%2);
329

    
330
    return ( quatIndex==BAD_CORNER_QUATS[index][0] ||
331
             quatIndex==BAD_CORNER_QUATS[index][1] ||
332
             quatIndex==BAD_CORNER_QUATS[index][2] ||
333
             quatIndex==BAD_CORNER_QUATS[index][3]  );
334
    }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

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

    
350
    return true;
351
    }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

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

    
367
    return true;
368
    }
369

    
370
///////////////////////////////////////////////////////////////////////////////////////////////////
371

    
372
  private void computePermittedAngles()
373
    {
374
    mPermittedDo = 0;
375

    
376
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
377
      {
378
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
379
      }
380

    
381
    mPermittedUp = 0;
382

    
383
    for(int angle=0; angle<BASIC_ANGLE[0]; angle++)
384
      {
385
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
386
      }
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

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

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

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

    
411
///////////////////////////////////////////////////////////////////////////////////////////////////
412

    
413
  private int makeQuat(int axis,int index)
414
    {
415
    if( axis==1 ) return 13;
416
    if( index<0 ) index+=12;
417
    return index;
418
    }
419

    
420
///////////////////////////////////////////////////////////////////////////////////////////////////
421

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

    
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437

    
438
  private void updateCornerQuats(int[] rotInfo)
439
    {
440
    int axis = rotInfo[0];
441
    int layer= rotInfo[1];
442
    int index=-rotInfo[2];
443

    
444
    int quat = makeQuat(axis,index);
445

    
446
    for(int corner=0; corner<8; corner++)
447
      {
448
      if( cornerBelongs(corner,axis,layer) )
449
        {
450
        int curr = mCornerQuat[corner];
451
        mCornerQuat[corner] = QUAT_MULT[quat][curr];
452
        }
453
      }
454
    }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457
// PUBLIC API
458

    
459
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
460
    {
461
    int layer, nextAngle;
462

    
463
    if( curr==0 )
464
      {
465
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
466
      mLastRot = rnd.nextInt(4);
467
      computePermittedAngles();
468
      }
469

    
470
    switch(mLastRot)
471
      {
472
      case LAST_SL: layer = rnd.nextInt(2);
473
                    nextAngle = getNextAngle(rnd,layer);
474

    
475
                    if( nextAngle==0 )
476
                      {
477
                      layer = 1-layer;
478
                      nextAngle = getNextAngleNotZero(rnd,layer);
479
                      }
480

    
481
                    scramble[curr][0] = 0;
482
                    scramble[curr][1] = 2*layer;
483
                    scramble[curr][2] = nextAngle;
484
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
485
                    updateCornerQuats(scramble[curr]);
486
                    break;
487
      case LAST_LO:
488
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
489
                    nextAngle = getNextAngle(rnd,layer);
490

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

    
509
                    break;
510
      case LAST_UL: scramble[curr][0] = 1;
511
                    scramble[curr][1] = rnd.nextInt(2);
512
                    scramble[curr][2] = 1;
513
                    mLastRot = LAST_SL;
514
                    updateCornerQuats(scramble[curr]);
515
                    computePermittedAngles();
516
                    break;
517
      }
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

    
522
  public boolean isSolved()
523
    {
524
    int index = CUBITS[0].mQuatIndex;
525

    
526
    for(int i=1; i<NUM_CUBITS; i++)
527
      {
528
      if( CUBITS[i].mQuatIndex != index ) return false;
529
      }
530

    
531
    return true;
532
    }
533

    
534
///////////////////////////////////////////////////////////////////////////////////////////////////
535

    
536
  public int getObjectName(int numLayers)
537
    {
538
    return R.string.squa1;
539
    }
540

    
541
///////////////////////////////////////////////////////////////////////////////////////////////////
542

    
543
  public int getInventor(int numLayers)
544
    {
545
    return R.string.squa1_inventor;
546
    }
547

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

    
550
  public int getComplexity(int numLayers)
551
    {
552
    return 9;
553
    }
554
}
(39-39/41)