Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistySquare1.java @ 57e86ed0

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
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshSquare;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35
import org.distorted.main.R;
36

    
37
import java.util.Random;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

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

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

    
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
      {-1.0f,-1.0f, 2.0f,-2.0f,-1.0f, 1.0f }
73
    };
74

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

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

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

    
107
  private static final int NUM_ST = STICKERS.length;
108

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

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

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

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

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

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

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  TwistySquare1(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
155
                DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
156
    {
157
    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU1, res, scrWidth);
158

    
159
    mLastRot = LAST_SL;
160
    mPermittedAngles = new int[2][BASIC_ANGLE[0]];
161
    mCornerQuat = new int[8];
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

    
166
  private Static4D getQuat(int cubit)
167
    {
168
    return QUATS[QUAT_NUMBER[cubit]];
169
    }
170

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

    
173
  MeshBase createCornerCubitMesh()
174
    {
175
    if( mMeshes[2]==null )
176
      {
177
      float[][] bands= new float[][]
178
        {
179
          {0.038f,35,0.9f,1.0f, 5,2,1},
180
          {0.001f,35,0.9f,1.0f, 5,2,1}
181
        };
182
      int[] bandIndexes   = new int[] { 0,1,0,0,1,1 };
183
      float[][] corners   = new float[][] { {0.05f,0.13f} };
184
      int[] cornerIndexes = new int[] { 0,0,0,-1,0,0,0,-1 };
185
      float[][] centers   = new float[][] { { -0.5f, 0.0f,-0.5f} };
186
      int[] centerIndexes = new int[] { -1,0,-1,-1,-1,0,-1,-1 };
187

    
188
      FactoryCubit factory = FactoryCubit.getInstance();
189
      factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
190
      mMeshes[2] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
191
                                              bands, bandIndexes,
192
                                              corners, cornerIndexes,
193
                                              centers, centerIndexes,
194
                                              getNumCubitFaces() );
195
      }
196
    return mMeshes[2].copy(true);
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  MeshBase createCubitMesh(int cubit, int numLayers)
202
    {
203
    if( mMeshes==null )
204
      {
205
      FactoryCubit factory = FactoryCubit.getInstance();
206
      factory.clear();
207
      mMeshes = new MeshBase[4];
208
      }
209

    
210
    MeshBase mesh;
211

    
212
         if( cubit< 2 ) mesh = createMiddleCubitMesh();
213
    else if( cubit<10 ) mesh = createEdgeCubitMesh();
214
    else                mesh = createCornerCubitMesh();
215

    
216
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
217
    mesh.apply(quat,0xffffffff,0);
218

    
219
    return mesh;
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
225
    {
226
    int COLORS = FACE_COLORS.length;
227
    int stickerType = face/COLORS;
228
    float R,S;
229

    
230
    switch(stickerType)
231
      {
232
      case 0:  R = 0.06f; S = 0.05f; break;
233
      case 1:  R = 0.04f; S = 0.04f; break;
234
      case 2:  R = 0.11f; S = 0.09f; break;
235
      case 3:  R = 0.03f; S = 0.05f; break;
236
      case 4:  R = 0.11f; S = 0.08f; break;
237
      case 5:  R = 0.08f; S = 0.08f; break;
238
      default: R = 0.00f; S = 0.00f; break;
239
      }
240

    
241
    FactorySticker factory = FactorySticker.getInstance();
242
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[stickerType], S, FACE_COLORS[face%COLORS], R);
243
    }
244

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

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

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  int getNumStickerTypes(int numLayers)
255
    {
256
    return STICKERS.length;
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260

    
261
  int getFaceColor(int cubit, int cubitface, int numLayers)
262
    {
263
    int type;
264

    
265
         if( cubit< 2 ) type = 0;
266
    else if( cubit<10 ) type = 1;
267
    else                type = 2;
268

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

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

    
276
  int computeBitmapFromRow(int rowBitmap, int axis)
277
    {
278
    int bitmap, initBitmap=0;
279

    
280
    while( initBitmap!=rowBitmap )
281
      {
282
      initBitmap = rowBitmap;
283

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

    
291
    return rowBitmap;
292
    }
293

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

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

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

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

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

    
319
    return false;
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

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

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

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335

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

    
348
    return true;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

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

    
365
    return true;
366
    }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
  private void computePermittedAngles()
371
    {
372
    mPermittedDo = 0;
373

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

    
379
    mPermittedUp = 0;
380

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

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

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

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

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

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

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

    
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419

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

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

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

    
442
    int quat = makeQuat(axis,index);
443

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

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455
// PUBLIC API
456

    
457
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
458
    {
459
    int layer, nextAngle;
460

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

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

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

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

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

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

    
518
///////////////////////////////////////////////////////////////////////////////////////////////////
519

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

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

    
529
    return true;
530
    }
531

    
532
///////////////////////////////////////////////////////////////////////////////////////////////////
533

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

    
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

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

    
546
///////////////////////////////////////////////////////////////////////////////////////////////////
547

    
548
  public int getComplexity(int numLayers)
549
    {
550
    return 9;
551
    }
552
}
(37-37/39)