Project

General

Profile

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

magiccube / src / main / java / org / distorted / helpers / ScrambleStateSquare1.java @ 4c49986e

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

    
22
import java.util.ArrayList;
23
import java.util.Random;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
// producer of the ScrambleStateGraph - but only for a single Twisty Puzzle, the 'Square-1'.
27

    
28
public class ScrambleStateSquare1
29
{
30
  private static final int INVALID_MOVE = -1;
31
  private static final int NUM_MOVES = 23;
32

    
33
  private int mDist;
34
  private boolean mFresh;
35
  private long mID;
36
  private final long[] mMoves;
37

    
38
  private final int[][] mPermittedAngles;
39
  private final int[] mCornerQuat, mTmp;
40

    
41
  // QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
42
  static final int[][] QUAT_MULT = new int[][]
43
    {
44
      {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
45
      {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
46
      {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
47
      {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
48
      {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
49
      {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
50
      {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
51
      {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
52
      {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
53
      {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
54
      { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
55
      { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
56
      { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
57
      { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
58
      { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
59
      { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
60
      { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
61
      { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
62
      { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
63
      { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
64
      { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
65
      { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
66
      { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
67
      { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
68
    };
69

    
70
  // quat indices that make corner cubits bandage the puzzle.
71
  private static final int[][] BAD_CORNER_QUATS = new int[][]
72
    {
73
      { 2, 8,17,23},
74
      { 5,11,14,20},
75
    };
76

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

    
79
  public ScrambleStateSquare1(long id, int dist)
80
    {
81
    mCornerQuat = new int[8];
82
    mTmp        = new int[8];
83
    mPermittedAngles = new int[2][12];
84

    
85
    mDist = dist;
86
    mFresh = true;
87
    mID = id;
88
    mMoves = createMoves(mID);
89
    }
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

    
93
  private void setNotFresh()
94
    {
95
    mFresh = false;
96
    }
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

    
100
  private boolean isFresh()
101
    {
102
    return mFresh;
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

    
107
  public static void computeGraph()
108
    {
109
    ArrayList<ScrambleStateSquare1> graph;
110

    
111
    ScrambleStateSquare1 bsg = new ScrambleStateSquare1(0,0);
112
    graph = new ArrayList<>();
113
    graph.add(bsg);
114

    
115
android.util.Log.e("D", "INSERTING");
116

    
117
    insertChildren(graph,0);
118

    
119
//android.util.Log.e("D", "PRUNING "+graph.size());
120

    
121
//    pruneGraph(graph);
122

    
123
android.util.Log.e("D", "REMAPPING "+graph.size());
124

    
125
    remapGraph(graph);
126

    
127
    int num = graph.size();
128
    android.util.Log.e("D", "\n"+num+" states\n");
129

    
130
    for(int i=0; i<num; i++)
131
      {
132
      bsg = graph.get(i);
133
      android.util.Log.e("D", formatMoves(bsg));
134
      }
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  private static void insertChildren(ArrayList<ScrambleStateSquare1> list, long id)
140
    {
141
    ScrambleStateSquare1 bsg = findState(list,id);
142

    
143
    if( bsg==null )
144
      {
145
      android.util.Log.e("D", "error: "+id+" doesn't exist");
146
      return;
147
      }
148

    
149
    int dist = bsg.mDist;
150
    if( dist>6 ) return;
151

    
152
    for(int i=0; i<NUM_MOVES; i++)
153
      {
154
      long moveID = bsg.getMoveID(i);
155

    
156
      if( moveID!=INVALID_MOVE )
157
        {
158
        ScrambleStateSquare1 tmp = findState(list,moveID);
159

    
160
        if( tmp==null )
161
          {
162
          tmp = new ScrambleStateSquare1(moveID,dist+1);
163
          list.add(tmp);
164
          }
165
        }
166
      }
167

    
168
    for(int i=0; i<NUM_MOVES; i++)
169
      {
170
      long moveID = bsg.getMoveID(i);
171

    
172
      if( moveID!=INVALID_MOVE )
173
        {
174
        ScrambleStateSquare1 tmp = findState(list,moveID);
175

    
176
        if( tmp.isFresh() )
177
          {
178
          tmp.setNotFresh();
179
          insertChildren(list,moveID);
180
          }
181
        }
182
      }
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  private static void pruneGraph(ArrayList<ScrambleStateSquare1> list)
188
    {
189
    int num = list.size(), numAxis;
190
    boolean pruned = false;
191
    ScrambleStateSquare1 bsg;
192

    
193
    for(int i=0; i<num; i++)
194
      {
195
      bsg = list.get(i);
196
      numAxis = bsg.numAxis();
197

    
198
      if( numAxis<2 )
199
        {
200
        list.remove(i);
201
        long id = bsg.getID();
202
        pruned = true;
203
        remapID(list,id,INVALID_MOVE);
204
        break;
205
        }
206
      }
207

    
208
    if( pruned ) pruneGraph(list);
209
    }
210

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

    
213
  private static void remapGraph(ArrayList<ScrambleStateSquare1> list)
214
    {
215
    long id;
216
    int num = list.size();
217
    ScrambleStateSquare1 bsg;
218

    
219
    for(int i=0; i<num; i++ )
220
      {
221
      bsg = list.get(i);
222
      id = bsg.getID();
223
      bsg.setID(i);
224
      remapID(list,id,i);
225
      }
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  private static void remapID(ArrayList<ScrambleStateSquare1> list, long id, long newId)
231
    {
232
    ScrambleStateSquare1 bsg;
233
    int size = list.size();
234

    
235
    for(int i=0; i<size; i++)
236
      {
237
      bsg = list.get(i);
238

    
239
      for(int j=0; j<NUM_MOVES; j++)
240
        {
241
        if( bsg.getMoveID(j)==id ) bsg.setMoveID(j,newId);
242
        }
243
      }
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  private static ScrambleStateSquare1 findState(ArrayList<ScrambleStateSquare1> list, long id)
249
    {
250
    ScrambleStateSquare1 bsg;
251
    int num = list.size();
252

    
253
    for(int i=0; i<num; i++)
254
      {
255
      bsg= list.get(i);
256
      if( bsg.getID() == id ) return bsg;
257
      }
258

    
259
    return null;
260
    }
261

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

    
264
  private static String formatMoves(ScrambleStateSquare1 bsg)
265
    {
266
    String x = getTable(bsg,0);
267
    String y = getTable(bsg,11);
268
    String z = getTable(bsg,12);
269

    
270
    //return "    new ScrambleStateGraph( new int[][] { "+x+", "+y+", "+z+" } ),";
271

    
272
    long id = bsg.getID();
273

    
274
    return id+" "+x+" , "+y+" , "+z;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private static String getTable(ScrambleStateSquare1 sc, int index)
280
    {
281
    String ret = "";
282
    long m;
283
    int half = (NUM_MOVES)/2;
284

    
285
    if( index==11 )
286
      {
287
      m = sc.getMoveID(index);
288
      if( m==INVALID_MOVE ) return formatL("{}");
289
      ret += formatRet(ret,0,1,m);
290
      }
291
    else
292
      {
293
      for(int i=0; i<half; i++)
294
        {
295
        m = sc.getMoveID(index+i);
296
        int row = index==0 ? 0:2;
297
        int angle = i+1;
298
        if( m!=INVALID_MOVE ) ret += formatRet(ret,row,angle,m);
299
        }
300
      }
301

    
302
    return formatL("{" + ret + "}");
303
    }
304

    
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306

    
307
  private static String formatRet(String str, int row, int angle, long id)
308
    {
309
    String ret = str.length()!=0 ? "  ,":"  ";
310

    
311
    ret += row;
312
    ret += angle<0 ? "," : ",";
313
    ret += angle;
314

    
315
         if( id< 10 ) ret += (",  "+id);
316
    else if( id<100 ) ret += (", " +id);
317
    else              ret += (","  +id);
318

    
319
    return ret;
320
    }
321

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

    
324
  private static final int LENGTH = 28;
325

    
326
  private static String formatL(String input)
327
    {
328
    int len = input.length();
329
    String ret = input;
330
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
331
    return ret;
332
    }
333

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

    
336
  private long getID()
337
    {
338
    return mID;
339
    }
340

    
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

    
343
  private void setID(long id)
344
    {
345
    mID = id;
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private long getMoveID(int index)
351
    {
352
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : -1;
353
    }
354

    
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356

    
357
  private void setMoveID(int index, long newID)
358
    {
359
    if( index>=0 && index<NUM_MOVES ) mMoves[index] = newID;
360
    }
361

    
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363

    
364
  private int numAxis()
365
    {
366
    int num = 0;
367
    int half = (NUM_MOVES)/2;
368

    
369
    for(int i=0; i<half; i++)
370
      {
371
      if( mMoves[i]!=INVALID_MOVE )
372
        {
373
        num++;
374
        break;
375
        }
376
      }
377

    
378
    for(int i=half; i<NUM_MOVES-1; i++)
379
      {
380
      if( mMoves[i]!=INVALID_MOVE )
381
        {
382
        num++;
383
        break;
384
        }
385
      }
386

    
387
    if( mMoves[NUM_MOVES-1]!=INVALID_MOVE ) num++;
388

    
389
    return num;
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393

    
394
  private long[] createMoves(long id)
395
    {
396
    long[] ret = new long[NUM_MOVES];
397
    fillCornerQuat(id);
398
    computePermittedAngles();
399

    
400
    generateUMoves(ret, 0);
401
    generateSMoves(ret,11);
402
    generateLMoves(ret,12);
403

    
404
    return ret;
405
    }
406

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

    
409
  private void generateUMoves(long[] table, int index)
410
    {
411
    for(int angle=1; angle<12; angle++)
412
      {
413
      table[index+angle-1] = mPermittedAngles[1][angle]==1 ? updateCornerQuats(0,2,angle) : INVALID_MOVE;
414
      }
415
    }
416

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

    
419
  private void generateLMoves(long[] table, int index)
420
    {
421
    for(int angle=1; angle<12; angle++)
422
      {
423
      table[index+angle-1] = mPermittedAngles[0][angle]==1 ? updateCornerQuats(0,0,angle) : INVALID_MOVE;
424
      }
425
    }
426

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

    
429
  private void generateSMoves(long[] table, int index)
430
    {
431
    table[index] = updateCornerQuats(1,1,1);
432
    }
433

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

    
436
  private void fillCornerQuat(long id)
437
    {
438
    int NUM_QUATS = 24;
439

    
440
    for(int i=0; i<8; i++)
441
      {
442
      mCornerQuat[i] = (int)(id%NUM_QUATS);
443
      id/=NUM_QUATS;
444
      }
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  private static long returnID(int[] cornerQuat)
450
    {
451
    int NUM_QUATS = 24;
452
    long mult=1,ret=0;
453

    
454
    for(int i=0; i<8; i++)
455
      {
456
      ret += mult*cornerQuat[i];
457
      mult*=NUM_QUATS;
458
      }
459

    
460
    return ret;
461
    }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
  private boolean cornerIsUp(int index)
466
    {
467
    return ((index<4) ^ (mCornerQuat[index]>=12));
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
  private boolean cornerIsLeft(int index)
473
    {
474
    int q = mCornerQuat[index];
475

    
476
    switch(index)
477
      {
478
      case 0:
479
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
480
      case 1:
481
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
482
      case 2:
483
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
484
      case 3:
485
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
486
      }
487

    
488
    return false;
489
    }
490

    
491
///////////////////////////////////////////////////////////////////////////////////////////////////
492

    
493
  private int makeQuat(int axis,int index)
494
    {
495
    if( axis==1 ) return 13;
496
    if( index<0 ) index+=12;
497
    return index;
498
    }
499

    
500
///////////////////////////////////////////////////////////////////////////////////////////////////
501

    
502
  private boolean cornerBelongs(int index, int axis, int layer)
503
    {
504
    if( axis==0 )
505
      {
506
      boolean up = cornerIsUp(index);
507
      return ((up && layer==2) || (!up && layer==0));
508
      }
509
    else
510
      {
511
      boolean le = cornerIsLeft(index);
512
      return ((le && layer==0) || (!le && layer==1));
513
      }
514
    }
515

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

    
518
  private long updateCornerQuats(int axis, int layer, int index)
519
    {
520
    int quat = makeQuat(axis,index);
521

    
522
    for(int corner=0; corner<8; corner++)
523
      {
524
      if( cornerBelongs(corner,axis,layer) )
525
        {
526
        int curr = mCornerQuat[corner];
527
        mTmp[corner] = QUAT_MULT[quat][curr];
528
        }
529
      else
530
        {
531
        mTmp[corner] = mCornerQuat[corner];
532
        }
533
      }
534

    
535
    return returnID(mTmp);
536
    }
537

    
538
///////////////////////////////////////////////////////////////////////////////////////////////////
539

    
540
  private boolean quatIsBad(int quatIndex, int corner)
541
    {
542
    int index = (corner%2);
543

    
544
    return ( quatIndex==BAD_CORNER_QUATS[index][0] ||
545
             quatIndex==BAD_CORNER_QUATS[index][1] ||
546
             quatIndex==BAD_CORNER_QUATS[index][2] ||
547
             quatIndex==BAD_CORNER_QUATS[index][3]  );
548
    }
549

    
550
///////////////////////////////////////////////////////////////////////////////////////////////////
551

    
552
  private int isPermittedDo(int angle)
553
    {
554
    for(int corner=0; corner<8; corner++)
555
      {
556
      if( !cornerIsUp(corner) )
557
        {
558
        int currQuat = mCornerQuat[corner];
559
        int finalQuat= QUAT_MULT[angle][currQuat];
560
        if( quatIsBad(finalQuat,corner) ) return 0;
561
        }
562
      }
563

    
564
    return 1;
565
    }
566

    
567
///////////////////////////////////////////////////////////////////////////////////////////////////
568

    
569
  private int isPermittedUp(int angle)
570
    {
571
    for(int corner=0; corner<8; corner++)
572
      {
573
      if( cornerIsUp(corner) )
574
        {
575
        int currQuat = mCornerQuat[corner];
576
        int finalQuat= QUAT_MULT[angle][currQuat];
577
        if( quatIsBad(finalQuat,corner) ) return 0;
578
        }
579
      }
580

    
581
    return 1;
582
    }
583

    
584
///////////////////////////////////////////////////////////////////////////////////////////////////
585

    
586
  private void computePermittedAngles()
587
    {
588
    for(int angle=0; angle<12; angle++)
589
      {
590
      mPermittedAngles[0][angle] = isPermittedDo(angle);
591
      mPermittedAngles[1][angle] = isPermittedUp(angle);
592
      }
593
    }
594
}
(11-11/15)