Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / ScrambleStateSquare1.java @ 198c5bf0

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

    
22
import java.util.ArrayList;
23

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

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

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

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

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

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

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

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

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

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

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

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

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

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

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

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

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

    
116
    insertChildren(graph,0);
117

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

    
120
//    pruneGraph(graph);
121

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

    
124
    remapGraph(graph);
125

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

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

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

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

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

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

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

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

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

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

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

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

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

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

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

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

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

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

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

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

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

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

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

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

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

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

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

    
258
    return null;
259
    }
260

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

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

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

    
271
    long id = bsg.getID();
272

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

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

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

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

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

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

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

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

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

    
318
    return ret;
319
    }
320

    
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322

    
323
  private static final int LENGTH = 28;
324

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

    
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

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

    
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341

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

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

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

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355

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

    
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362

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

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

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

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

    
388
    return num;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

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

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

    
403
    return ret;
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407

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

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

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

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

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

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

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

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

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

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

    
459
    return ret;
460
    }
461

    
462
///////////////////////////////////////////////////////////////////////////////////////////////////
463

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

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470

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

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

    
487
    return false;
488
    }
489

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491

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

    
499
///////////////////////////////////////////////////////////////////////////////////////////////////
500

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

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516

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

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

    
534
    return returnID(mTmp);
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538

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

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

    
549
///////////////////////////////////////////////////////////////////////////////////////////////////
550

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

    
563
    return 1;
564
    }
565

    
566
///////////////////////////////////////////////////////////////////////////////////////////////////
567

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

    
580
    return 1;
581
    }
582

    
583
///////////////////////////////////////////////////////////////////////////////////////////////////
584

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