Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / ObjectSignature.java @ 1d581993

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.helpers;
21

    
22
import org.distorted.objectlib.main.ObjectType;
23

    
24
import java.util.ArrayList;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27

    
28
public class ObjectSignature
29
{
30
  private long mSignature1, mSignature2, mSignature3;
31
  private int[] mLayer;
32
  private float[][][] mAllCycles;
33
  private float[][] mCubitTouch;
34
  private int mNumCubitTouches, mNumCycles;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37
// built-in objects
38

    
39
  public ObjectSignature(ObjectType type)
40
    {
41
    mSignature1 = 0;
42
    mSignature2 = 0;
43
    mSignature3 = type.ordinal();
44
    }
45

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

    
48
  public ObjectSignature(ObjectSignature sig)
49
    {
50
    mSignature1 = sig.mSignature1;
51
    mSignature2 = sig.mSignature2;
52
    mSignature3 = sig.mSignature3;
53

    
54
    mLayer      = sig.mLayer;
55
    mAllCycles  = sig.mAllCycles;
56
    mCubitTouch = sig.mCubitTouch;
57

    
58
    mNumCycles       = sig.mNumCycles;
59
    mNumCubitTouches = sig.mNumCubitTouches;
60
    }
61

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63
// built-in bandaged 3x3s; objects created from JSON (version1)
64

    
65
  public ObjectSignature(long signature)
66
    {
67
    mSignature1 = 0;
68
    mSignature2 = 0;
69
    mSignature3 = signature;
70
    }
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
// objects created from JSON (version2)
74

    
75
  public ObjectSignature(long signature1, long signature2, long signature3)
76
    {
77
    mSignature1 = signature1;
78
    mSignature2 = signature2;
79
    mSignature3 = signature3;
80
    }
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
// Locally created bandaged cuboids 1<=N,M,K<=5
84
// This is the 'Andreas signature' of a bandaged cube.
85
// https://twistypuzzles.com/forum/viewtopic.php?p=415466#p415466
86

    
87
  public ObjectSignature(int lenx, int leny, int lenz, float[][] position)
88
    {
89
    mLayer = new int[] {lenx,leny,lenz};
90

    
91
    prepareCubitTouch();
92
    prepareAllCycles();
93

    
94
    for(float[] pos : position)
95
      {
96
      int numCenters = pos.length/3;
97

    
98
      for(int i=0; i<numCenters; i++)
99
        for(int j=i+1; j<numCenters; j++)
100
          {
101
          float x1 = pos[3*i  ];
102
          float y1 = pos[3*i+1];
103
          float z1 = pos[3*i+2];
104
          float x2 = pos[3*i  ];
105
          float y2 = pos[3*i+1];
106
          float z2 = pos[3*i+2];
107

    
108
          if(areNeighbours(x1-x2,y1-y2,z1-z2))
109
            {
110
            float xc = (x1+y1)/2;
111
            float yc = (y1+y2)/2;
112
            float zc = (z1+z2)/2;
113

    
114
            int bitIndex = getIndexOfCubitTouch(xc,yc,zc);
115
            setBit(bitIndex,1);
116
            }
117
          }
118
      }
119
    }
120

    
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

    
123
  public void setSignature(ObjectSignature sig)
124
    {
125
    mSignature1 = sig.mSignature1;
126
    mSignature2 = sig.mSignature2;
127
    mSignature3 = sig.mSignature3;
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

    
132
  public void setSignature(int sig)
133
    {
134
    mSignature1 = 0;
135
    mSignature2 = 0;
136
    mSignature3 = sig;
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  public boolean isEqual(ObjectSignature sig)
142
    {
143
    return mSignature1==sig.mSignature1 && mSignature2==sig.mSignature2 && mSignature3==sig.mSignature3;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  public long getLong1()
149
    {
150
    return mSignature1;
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
  public long getLong2()
156
    {
157
    return mSignature2;
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  public long getLong3()
163
    {
164
    return mSignature3;
165
    }
166

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

    
169
  public String getString()
170
    {
171
    return mSignature1+"_"+mSignature2+"_"+mSignature3;
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  public boolean isUnblockedFromLeft(int axis, int layer)
177
    {
178
    if(layer>0)
179
      for(int index=0; index<mNumCubitTouches; index++)
180
        if( getBit(index)!=0 )
181
          {
182
          float[] touch = getCubitTouchOfIndex(index);
183
          if( belongsToTheLeft(touch,axis,layer) ) return false;
184
          }
185

    
186
    return true;
187
    }
188

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

    
191
  public ObjectSignature turn(int axis, int layer, int turn)
192
    {
193
    ObjectSignature ret = new ObjectSignature(this);
194

    
195
    for(int i=0; i<mNumCycles; i++)
196
      {
197
      float[][] cyc = mAllCycles[i];
198
      float[] p0 = cyc[0];
199
      float[] p1 = cyc[1];
200

    
201
      if( (belongsToTheLeft(p0,axis,layer) && belongsToTheLeft(p1,axis,layer)) ||
202
          (belongsToTheCent(p0,axis,layer) && belongsToTheCent(p1,axis,layer))  )
203
        {
204
        ret.cycle(turn,cyc);
205
        }
206
      }
207

    
208
    return ret;
209
    }
210

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

    
213
  private void cycle(int turn, float[][] cyc)
214
    {
215
    int numPoints = cyc.length;
216

    
217
    if( numPoints==2 )
218
      {
219
      float[] p0 = cyc[0];
220
      float[] p1 = cyc[1];
221

    
222
      int index0 = getIndexOfCubitTouch(p0[0],p0[1],p0[2]);
223
      int index1 = getIndexOfCubitTouch(p1[0],p1[1],p1[2]);
224

    
225
      long b0 = getBit(index0);
226
      long b1 = getBit(index1);
227

    
228
      setBit(index1,b0);
229
      setBit(index0,b1);
230
      }
231
    else if( numPoints==4 )
232
      {
233
      float[] p0 = cyc[0];
234
      float[] p1 = cyc[1];
235
      float[] p2 = cyc[2];
236
      float[] p3 = cyc[3];
237

    
238
      int index0 = getIndexOfCubitTouch(p0[0],p0[1],p0[2]);
239
      int index1 = getIndexOfCubitTouch(p1[0],p1[1],p1[2]);
240
      int index2 = getIndexOfCubitTouch(p2[0],p2[1],p2[2]);
241
      int index3 = getIndexOfCubitTouch(p3[0],p3[1],p3[2]);
242

    
243
      long b0 = getBit(index0);
244
      long b1 = getBit(index1);
245
      long b2 = getBit(index2);
246
      long b3 = getBit(index3);
247

    
248
      switch(turn)
249
        {
250
        case 1: setBit(index0,b3);
251
                setBit(index1,b0);
252
                setBit(index2,b1);
253
                setBit(index3,b2);
254
                break;
255
        case 2: setBit(index0,b2);
256
                setBit(index1,b3);
257
                setBit(index2,b0);
258
                setBit(index3,b1);
259
                break;
260
        case 3: setBit(index0,b1);
261
                setBit(index1,b2);
262
                setBit(index2,b3);
263
                setBit(index3,b0);
264
                break;
265
        }
266
      }
267
    else
268
      {
269
      android.util.Log.e("D", "error in cycle, numPoints="+numPoints);
270
      }
271
    }
272

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

    
275
  private void prepareCubitTouch()
276
    {
277
    int numCenters = mLayer[0]*mLayer[1]*mLayer[2];
278
    if( mLayer[0]>1 && mLayer[1]>1 && mLayer[2]>1 ) numCenters -= (mLayer[0]-2)*(mLayer[1]-2)*(mLayer[2]-2);
279

    
280
    float[][] centers = new float[numCenters][];
281
    int index = 0;
282

    
283
    for(int i = 0; i<mLayer[0]; i++)
284
      for(int j = 0; j<mLayer[1]; j++)
285
        for(int k = 0; k<mLayer[2]; k++)
286
          if( (i==0) || (i==mLayer[0]-1) || (j==0) || (j==mLayer[1]-1) || (k==0) || (k==mLayer[2]-1) )
287
            {
288
            centers[index++] = new float[] { i+0.5f*(1-mLayer[0]), j+0.5f*(1-mLayer[1]), k+0.5f*(1-mLayer[2]) };
289
            }
290

    
291
    ArrayList<float[]> mTouch = new ArrayList<>();
292

    
293
    for(int i=0; i<numCenters; i++)
294
      for(int j=i+1; j<numCenters; j++)
295
        {
296
        float[] c0 = centers[i];
297
        float[] c1 = centers[j];
298

    
299
        float x1 = c0[0];
300
        float y1 = c0[1];
301
        float z1 = c0[2];
302
        float x2 = c1[0];
303
        float y2 = c1[1];
304
        float z2 = c1[2];
305

    
306
        if( areNeighbours(x1-x2,y1-y2,z1-z2) )
307
          {
308
          float xc = (x1+y1)/2;
309
          float yc = (y1+y2)/2;
310
          float zc = (z1+z2)/2;
311

    
312
          float[] touch = new float[] {xc,yc,zc};
313
          mTouch.add(touch);
314
          }
315
        }
316

    
317
    mNumCubitTouches = mTouch.size();
318
    mCubitTouch = new float[mNumCubitTouches][];
319
    for(int i=0; i<mNumCubitTouches; i++) mCubitTouch[i] = mTouch.remove(0);
320
    }
321

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

    
324
  private void prepareAllCycles()
325
    {
326
    ArrayList<float[][]> cycles = new ArrayList<>();
327

    
328
    boolean[] longTurn = new boolean[] { mLayer[1]==mLayer[2], mLayer[0]==mLayer[2], mLayer[0]==mLayer[1] };
329

    
330
    for(int i=0; i<mNumCubitTouches; i++)
331
      for(int axis=0; axis<3; axis++)
332
        {
333
        if( longTurn[axis] )
334
          {
335
          int i0 = rotateIndex(axis,i);
336
          if( i0<i ) continue;
337
          int i1 = rotateIndex(axis,i0);
338
          if( i1<i ) continue;
339
          int i2 = rotateIndex(axis,i1);
340
          if( i2<i ) continue;
341

    
342
          float[] f0 = getCubitTouchOfIndex(i);
343
          float[] f1 = getCubitTouchOfIndex(i0);
344
          float[] f2 = getCubitTouchOfIndex(i1);
345
          float[] f3 = getCubitTouchOfIndex(i2);
346

    
347
          float[][] cycle = new float[][] { f0,f1,f2,f3 };
348
          cycles.add(cycle);
349
          }
350
        else
351
          {
352
          int i0 = rotateIndex2(axis,i);
353
          if( i0<i ) continue;
354

    
355
          float[] f0 = getCubitTouchOfIndex(i);
356
          float[] f1 = getCubitTouchOfIndex(i0);
357

    
358
          float[][] cycle = new float[][] { f0,f1 };
359
          cycles.add(cycle);
360
          }
361
        }
362

    
363
    mNumCycles = cycles.size();
364
    mAllCycles = new float[mNumCycles][][];
365
    for(int i=0; i<mNumCycles; i++) mAllCycles[i] = cycles.remove(0);
366
    }
367

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

    
370
  private int rotateIndex(int axis, int index)
371
    {
372
    float[] touch = getCubitTouchOfIndex(index);
373

    
374
    switch(axis)
375
      {
376
      case 0: return getIndexOfCubitTouch(+touch[0],+touch[2],-touch[1]);
377
      case 1: return getIndexOfCubitTouch(-touch[2],+touch[1],+touch[0]);
378
      case 2: return getIndexOfCubitTouch(+touch[1],-touch[0],+touch[2]);
379
      }
380

    
381
    return -1;
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385

    
386
  private int rotateIndex2(int axis, int index)
387
    {
388
    float[] touch = getCubitTouchOfIndex(index);
389

    
390
    switch(axis)
391
      {
392
      case 0: return getIndexOfCubitTouch(+touch[0],-touch[1],-touch[2]);
393
      case 1: return getIndexOfCubitTouch(-touch[0],+touch[1],-touch[2]);
394
      case 2: return getIndexOfCubitTouch(-touch[0],-touch[1],+touch[2]);
395
      }
396

    
397
    return -1;
398
    }
399

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

    
402
  private boolean belongsToTheLeft(float[] point, int axis, int layer)
403
    {
404
    return 2*point[axis]+mLayer[axis] == 2*layer;
405
    }
406

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

    
409
  private boolean belongsToTheCent(float[] point, int axis, int layer)
410
    {
411
    return 2*point[axis]+mLayer[axis] == 2*layer+1;
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
  private int getIndexOfCubitTouch(float x, float y, float z)
417
    {
418
    for(int i=0; i<mNumCubitTouches; i++)
419
      {
420
      float[] touch = mCubitTouch[i];
421
      if( touch[0]==x && touch[1]==y && touch[2]==z ) return i;
422
      }
423

    
424
    return -1;
425
    }
426

    
427
///////////////////////////////////////////////////////////////////////////////////////////////////
428

    
429
  private float[] getCubitTouchOfIndex(int index)
430
    {
431
    return mCubitTouch[index];
432
    }
433

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

    
436
  private boolean areNeighbours(float dx, float dy, float dz)
437
    {
438
    return dx*dx+dy*dy+dz*dz<1.1f;
439
    }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
  private long getBit(int index)
444
    {
445
    switch(index/64)
446
      {
447
      case 0: return (mSignature3>>(index%64))&0x1;
448
      case 1: return (mSignature2>>(index%64))&0x1;
449
      case 2: return (mSignature1>>(index%64))&0x1;
450
      default: android.util.Log.e("D", "error in getBit, index="+index);
451
      }
452

    
453
    return 0L;
454
    }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457

    
458
  private void setBit(int index, long bit)
459
    {
460
    long diff = (1L<<(index%64));
461

    
462
    switch(index/64)
463
      {
464
      case 0: if( bit!=0 ) mSignature3 |= diff;
465
              else         mSignature3 &=~diff;
466
              break;
467
      case 1: if( bit!=0 ) mSignature2 |= diff;
468
              else         mSignature2 &=~diff;
469
              break;
470
      case 2: if( bit!=0 ) mSignature1 |= diff;
471
              else         mSignature1 &=~diff;
472
              break;
473
      default: android.util.Log.e("D", "error in setBit, index="+index);
474
      }
475
    }
476
}
(9-9/11)