Revision 1d581993
Added by Leszek Koltunski about 2 years ago
src/main/java/org/distorted/objectlib/scrambling/ScrambleStateBandagedCuboid.java | ||
---|---|---|
19 | 19 |
|
20 | 20 |
package org.distorted.objectlib.scrambling; |
21 | 21 |
|
22 |
import java.util.LinkedHashMap; |
|
23 |
import java.util.Iterator; |
|
24 |
import java.util.Map; |
|
25 |
|
|
26 | 22 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
27 |
// Producer of the ScrambleStateGraph for any bandaged 3x3x3. |
|
23 |
// Info about a scramble state of any bandaged cuboid. |
|
24 |
|
|
25 |
import org.distorted.objectlib.helpers.ObjectSignature; |
|
28 | 26 |
|
29 | 27 |
public class ScrambleStateBandagedCuboid |
30 | 28 |
{ |
29 |
public static int MAX_SUPPORTED_SIZE = 5; |
|
30 |
|
|
31 | 31 |
public static final int AXIS_NONE = -1; |
32 | 32 |
public static final int AXIS_X = 0; |
33 | 33 |
public static final int AXIS_Y = 1; |
34 | 34 |
public static final int AXIS_Z = 2; |
35 | 35 |
|
36 |
private static final long INVALID_MOVE = -1; |
|
37 |
private static final int NUM_MOVES = 27; |
|
38 |
|
|
39 |
private static final int LAYER_L = 0; |
|
40 |
private static final int LAYER_M = 1; |
|
41 |
private static final int LAYER_R = 2; |
|
42 |
|
|
43 |
private long mID; |
|
44 |
private int mDistance; |
|
45 |
private final long[] mMoves; |
|
36 |
private final ObjectSignature[] mMoves; |
|
37 |
private final ObjectSignature mSignature; |
|
38 |
private final int[] mLayer, mTurns; |
|
39 |
private final int mNumMoves; |
|
40 |
private final int mStartX, mStartY, mStartZ; |
|
41 |
private final boolean[][] mIsUnblocked; |
|
46 | 42 |
|
47 | 43 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
48 | 44 |
|
49 |
public ScrambleStateBandagedCuboid(long id)
|
|
45 |
public ScrambleStateBandagedCuboid(int x, int y, int z, ObjectSignature signature)
|
|
50 | 46 |
{ |
51 |
mDistance = -1; |
|
52 |
mID = id; |
|
53 |
mMoves = createMoves(mID); |
|
47 |
mLayer = new int[3]; |
|
48 |
mTurns = new int[3]; |
|
49 |
|
|
50 |
mIsUnblocked = new boolean[3][MAX_SUPPORTED_SIZE]; |
|
51 |
|
|
52 |
mLayer[0] = x; |
|
53 |
mLayer[1] = y; |
|
54 |
mLayer[2] = z; |
|
55 |
|
|
56 |
mTurns[0] = mLayer[1]==mLayer[2] ? 3:1; |
|
57 |
mTurns[1] = mLayer[0]==mLayer[2] ? 3:1; |
|
58 |
mTurns[2] = mLayer[0]==mLayer[1] ? 3:1; |
|
59 |
|
|
60 |
int xMoves = mLayer[0]>1 ? mTurns[0]*mLayer[0] : 0; |
|
61 |
int yMoves = mLayer[1]>1 ? mTurns[1]*mLayer[1] : 0; |
|
62 |
int zMoves = mLayer[2]>1 ? mTurns[2]*mLayer[2] : 0; |
|
63 |
|
|
64 |
mNumMoves = xMoves + yMoves + zMoves; |
|
65 |
|
|
66 |
mStartX = 0; |
|
67 |
mStartY = xMoves; |
|
68 |
mStartZ = xMoves + yMoves; |
|
69 |
|
|
70 |
mSignature = signature; |
|
71 |
|
|
72 |
mMoves = createMoves(); |
|
73 |
|
|
74 |
|
|
75 |
android.util.Log.d("D", "sig: "+mSignature.getString() ); |
|
76 |
printMoves(); |
|
77 |
|
|
54 | 78 |
} |
55 | 79 |
|
56 | 80 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
57 | 81 |
|
58 |
public long getID()
|
|
82 |
public ObjectSignature getSignature()
|
|
59 | 83 |
{ |
60 |
return mID;
|
|
84 |
return mSignature;
|
|
61 | 85 |
} |
62 | 86 |
|
63 | 87 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
64 | 88 |
|
65 |
private void setID(long id)
|
|
89 |
public ObjectSignature getMove(int index)
|
|
66 | 90 |
{ |
67 |
mID = id;
|
|
91 |
return (index>=0 && index<mNumMoves) ? mMoves[index] : null;
|
|
68 | 92 |
} |
69 | 93 |
|
70 | 94 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
71 | 95 |
|
72 |
public long getMove(int index)
|
|
96 |
public void removeMoves(ObjectSignature signature)
|
|
73 | 97 |
{ |
74 |
return (index>=0 && index<NUM_MOVES) ? mMoves[index] : INVALID_MOVE; |
|
98 |
for(int m=0; m<mNumMoves; m++) |
|
99 |
if( signature.isEqual(mMoves[m]) ) mMoves[m]=null; |
|
75 | 100 |
} |
76 | 101 |
|
77 | 102 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
80 | 105 |
{ |
81 | 106 |
int num = 0; |
82 | 107 |
|
83 |
if( mMoves[ 0]!=INVALID_MOVE || mMoves[ 1]!=INVALID_MOVE || mMoves[ 2]!=INVALID_MOVE || |
|
84 |
mMoves[ 3]!=INVALID_MOVE || mMoves[ 4]!=INVALID_MOVE || mMoves[ 5]!=INVALID_MOVE || |
|
85 |
mMoves[ 6]!=INVALID_MOVE || mMoves[ 7]!=INVALID_MOVE || mMoves[ 8]!=INVALID_MOVE ) num++; |
|
86 |
|
|
87 |
if( mMoves[ 9]!=INVALID_MOVE || mMoves[10]!=INVALID_MOVE || mMoves[11]!=INVALID_MOVE || |
|
88 |
mMoves[12]!=INVALID_MOVE || mMoves[13]!=INVALID_MOVE || mMoves[14]!=INVALID_MOVE || |
|
89 |
mMoves[15]!=INVALID_MOVE || mMoves[16]!=INVALID_MOVE || mMoves[17]!=INVALID_MOVE ) num++; |
|
90 |
|
|
91 |
if( mMoves[18]!=INVALID_MOVE || mMoves[19]!=INVALID_MOVE || mMoves[20]!=INVALID_MOVE || |
|
92 |
mMoves[21]!=INVALID_MOVE || mMoves[22]!=INVALID_MOVE || mMoves[23]!=INVALID_MOVE || |
|
93 |
mMoves[24]!=INVALID_MOVE || mMoves[25]!=INVALID_MOVE || mMoves[26]!=INVALID_MOVE ) num++; |
|
108 |
for(int x=mStartX; x<mStartY ; x++) if( mMoves[x]!=null ) { num++; break; } |
|
109 |
for(int y=mStartY; y<mStartZ ; y++) if( mMoves[y]!=null ) { num++; break; } |
|
110 |
for(int z=mStartZ; z<mNumMoves; z++) if( mMoves[z]!=null ) { num++; break; } |
|
94 | 111 |
|
95 | 112 |
return num; |
96 | 113 |
} |
... | ... | |
100 | 117 |
private int numXMoves() |
101 | 118 |
{ |
102 | 119 |
int num=0; |
103 |
|
|
104 |
if( mMoves[ 0]!=INVALID_MOVE ) num++; |
|
105 |
if( mMoves[ 1]!=INVALID_MOVE ) num++; |
|
106 |
if( mMoves[ 2]!=INVALID_MOVE ) num++; |
|
107 |
if( mMoves[ 3]!=INVALID_MOVE ) num++; |
|
108 |
if( mMoves[ 4]!=INVALID_MOVE ) num++; |
|
109 |
if( mMoves[ 5]!=INVALID_MOVE ) num++; |
|
110 |
if( mMoves[ 6]!=INVALID_MOVE ) num++; |
|
111 |
if( mMoves[ 7]!=INVALID_MOVE ) num++; |
|
112 |
if( mMoves[ 8]!=INVALID_MOVE ) num++; |
|
113 |
|
|
120 |
for(int x=mStartX; x<mStartY; x++) if( mMoves[x]!=null ) num++; |
|
114 | 121 |
return num; |
115 | 122 |
} |
116 | 123 |
|
... | ... | |
119 | 126 |
private int numYMoves() |
120 | 127 |
{ |
121 | 128 |
int num=0; |
122 |
|
|
123 |
if( mMoves[ 9]!=INVALID_MOVE ) num++; |
|
124 |
if( mMoves[10]!=INVALID_MOVE ) num++; |
|
125 |
if( mMoves[11]!=INVALID_MOVE ) num++; |
|
126 |
if( mMoves[12]!=INVALID_MOVE ) num++; |
|
127 |
if( mMoves[13]!=INVALID_MOVE ) num++; |
|
128 |
if( mMoves[14]!=INVALID_MOVE ) num++; |
|
129 |
if( mMoves[15]!=INVALID_MOVE ) num++; |
|
130 |
if( mMoves[16]!=INVALID_MOVE ) num++; |
|
131 |
if( mMoves[17]!=INVALID_MOVE ) num++; |
|
132 |
|
|
129 |
for(int y=mStartY; y<mStartZ; y++) if( mMoves[y]!=null ) num++; |
|
133 | 130 |
return num; |
134 | 131 |
} |
135 | 132 |
|
... | ... | |
138 | 135 |
private int numZMoves() |
139 | 136 |
{ |
140 | 137 |
int num=0; |
141 |
|
|
142 |
if( mMoves[18]!=INVALID_MOVE ) num++; |
|
143 |
if( mMoves[19]!=INVALID_MOVE ) num++; |
|
144 |
if( mMoves[20]!=INVALID_MOVE ) num++; |
|
145 |
if( mMoves[21]!=INVALID_MOVE ) num++; |
|
146 |
if( mMoves[22]!=INVALID_MOVE ) num++; |
|
147 |
if( mMoves[23]!=INVALID_MOVE ) num++; |
|
148 |
if( mMoves[24]!=INVALID_MOVE ) num++; |
|
149 |
if( mMoves[25]!=INVALID_MOVE ) num++; |
|
150 |
if( mMoves[26]!=INVALID_MOVE ) num++; |
|
151 |
|
|
138 |
for(int z=mStartZ; z<mNumMoves; z++) if( mMoves[z]!=null ) num++; |
|
152 | 139 |
return num; |
153 | 140 |
} |
154 | 141 |
|
... | ... | |
170 | 157 |
case AXIS_Z: return numXMoves()+numYMoves(); |
171 | 158 |
} |
172 | 159 |
|
173 |
int ret= numXMoves()+numYMoves()+numZMoves(); |
|
174 |
|
|
175 |
//android.util.Log.e("D", "numMoves returning "+ret+" "+formatMoves() ); |
|
176 |
|
|
177 |
return ret; |
|
160 |
return numXMoves()+numYMoves()+numZMoves(); |
|
178 | 161 |
} |
179 | 162 |
|
180 | 163 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
183 | 166 |
{ |
184 | 167 |
int num = 0; |
185 | 168 |
|
186 |
for(int m=0; m<NUM_MOVES; m++)
|
|
169 |
if( excludedAxis!=0 )
|
|
187 | 170 |
{ |
188 |
if( (m/9)!=excludedAxis && mMoves[m]!=INVALID_MOVE) |
|
189 |
{ |
|
190 |
if( num==n ) return m; |
|
191 |
num++; |
|
192 |
} |
|
193 |
} |
|
194 |
|
|
195 |
return -1; |
|
196 |
} |
|
197 |
|
|
198 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
199 |
|
|
200 |
public void removeMoves(long signature) |
|
201 |
{ |
|
202 |
for(int m=0; m<NUM_MOVES; m++) |
|
203 |
if( signature==mMoves[m] ) mMoves[m]=INVALID_MOVE; |
|
204 |
} |
|
205 |
|
|
206 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
207 |
|
|
208 |
private void setMove(int index, long newMove) |
|
209 |
{ |
|
210 |
if( index>=0 && index<NUM_MOVES ) mMoves[index] = newMove; |
|
211 |
} |
|
212 |
|
|
213 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
214 |
|
|
215 |
public String formatMoves() |
|
216 |
{ |
|
217 |
String x = getTable( 0); |
|
218 |
String y = getTable( 9); |
|
219 |
String z = getTable(18); |
|
220 |
|
|
221 |
return mID+"\n"+x+"\n"+y+"\n"+z; |
|
222 |
} |
|
223 |
|
|
224 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
225 |
|
|
226 |
private String getTable(int index) |
|
227 |
{ |
|
228 |
long m0 = getMove(index ); |
|
229 |
long m1 = getMove(index+1); |
|
230 |
long m2 = getMove(index+2); |
|
231 |
long m3 = getMove(index+3); |
|
232 |
long m4 = getMove(index+4); |
|
233 |
long m5 = getMove(index+5); |
|
234 |
long m6 = getMove(index+6); |
|
235 |
long m7 = getMove(index+7); |
|
236 |
long m8 = getMove(index+8); |
|
237 |
|
|
238 |
String ret = ""; |
|
239 |
|
|
240 |
if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0); |
|
241 |
if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1); |
|
242 |
if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2); |
|
243 |
if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3); |
|
244 |
if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4); |
|
245 |
if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5); |
|
246 |
if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6); |
|
247 |
if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7); |
|
248 |
if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8); |
|
249 |
|
|
250 |
return formatL("{" + ret + "}"); |
|
251 |
} |
|
252 |
|
|
253 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
254 |
|
|
255 |
private int[] getMoves(int index) |
|
256 |
{ |
|
257 |
int numValid = 0; |
|
258 |
for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++; |
|
259 |
|
|
260 |
int[] ret = new int[3*numValid]; |
|
261 |
|
|
262 |
long m0 = getMove(index ); |
|
263 |
long m1 = getMove(index+1); |
|
264 |
long m2 = getMove(index+2); |
|
265 |
long m3 = getMove(index+3); |
|
266 |
long m4 = getMove(index+4); |
|
267 |
long m5 = getMove(index+5); |
|
268 |
long m6 = getMove(index+6); |
|
269 |
long m7 = getMove(index+7); |
|
270 |
long m8 = getMove(index+8); |
|
271 |
|
|
272 |
int pointer=0; |
|
273 |
|
|
274 |
if( m0!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]=-1; ret[pointer+2]= (int)m0; pointer+=3; } |
|
275 |
if( m1!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 2; ret[pointer+2]= (int)m1; pointer+=3; } |
|
276 |
if( m2!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 1; ret[pointer+2]= (int)m2; pointer+=3; } |
|
277 |
if( m3!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]=-1; ret[pointer+2]= (int)m3; pointer+=3; } |
|
278 |
if( m4!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 2; ret[pointer+2]= (int)m4; pointer+=3; } |
|
279 |
if( m5!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 1; ret[pointer+2]= (int)m5; pointer+=3; } |
|
280 |
if( m6!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]=-1; ret[pointer+2]= (int)m6; pointer+=3; } |
|
281 |
if( m7!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 2; ret[pointer+2]= (int)m7; pointer+=3; } |
|
282 |
if( m8!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 1; ret[pointer+2]= (int)m8; pointer+=3; } |
|
283 |
|
|
284 |
return ret; |
|
285 |
} |
|
286 |
|
|
287 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
288 |
|
|
289 |
private ScrambleState produceScrambleState() |
|
290 |
{ |
|
291 |
int[] xMoves = getMoves(0); |
|
292 |
int[] yMoves = getMoves(9); |
|
293 |
int[] zMoves = getMoves(18); |
|
294 |
|
|
295 |
int[][] moves = { xMoves,yMoves,zMoves }; |
|
296 |
|
|
297 |
return new ScrambleState( moves ); |
|
298 |
} |
|
299 |
|
|
300 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
301 |
// STATIC STUFF |
|
302 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
303 |
|
|
304 |
public static ScrambleState[] computeGraph(long id) |
|
305 |
{ |
|
306 |
ScrambleStateBandagedCuboid bsg = new ScrambleStateBandagedCuboid(id); |
|
307 |
Map<Long, ScrambleStateBandagedCuboid> graph = new LinkedHashMap<>(); |
|
308 |
graph.put(id,bsg); |
|
309 |
|
|
310 |
insertChildren(graph,id); |
|
311 |
// if there's only one state, do not prune moves which point to itself |
|
312 |
if(graph.size()>1) pruneGraph(graph,id); |
|
313 |
computeDistance(graph,id,0); |
|
314 |
removeDisconnectedParts(graph); |
|
315 |
remapGraph(graph); |
|
316 |
|
|
317 |
int num = graph.size(); |
|
318 |
ScrambleState[] ret = new ScrambleState[num]; |
|
319 |
|
|
320 |
for (Map.Entry<Long, ScrambleStateBandagedCuboid> entry : graph.entrySet()) |
|
321 |
{ |
|
322 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
323 |
int mid = (int)value.mID; |
|
324 |
ret[mid] = value.produceScrambleState(); |
|
325 |
} |
|
326 |
|
|
327 |
return ret; |
|
328 |
} |
|
329 |
|
|
330 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
331 |
|
|
332 |
private static void insertChildren(Map<Long, ScrambleStateBandagedCuboid> map, long id) |
|
333 |
{ |
|
334 |
ScrambleStateBandagedCuboid bsg = findState(map,id); |
|
335 |
|
|
336 |
if( bsg==null ) |
|
337 |
{ |
|
338 |
android.util.Log.e("D", "error: "+id+" doesn't exist"); |
|
339 |
return; |
|
340 |
} |
|
341 |
|
|
342 |
for(int i=0; i<NUM_MOVES; i++) |
|
343 |
{ |
|
344 |
long move = bsg.getMove(i); |
|
345 |
|
|
346 |
if( move!=INVALID_MOVE ) |
|
347 |
{ |
|
348 |
ScrambleStateBandagedCuboid tmp = findState(map,move); |
|
349 |
|
|
350 |
if( tmp==null ) |
|
171 |
for(int m=mStartX; m<mStartY; m++) |
|
172 |
if( mMoves[m]!=null ) |
|
351 | 173 |
{ |
352 |
tmp = new ScrambleStateBandagedCuboid(move); |
|
353 |
map.put(move,tmp); |
|
354 |
insertChildren(map,move); |
|
174 |
if( num==n ) return m; |
|
175 |
num++; |
|
355 | 176 |
} |
356 |
} |
|
357 | 177 |
} |
358 |
} |
|
359 | 178 |
|
360 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
361 |
|
|
362 |
private static void pruneGraph(Map<Long, ScrambleStateBandagedCuboid> map, long startingID) |
|
363 |
{ |
|
364 |
boolean pruned = false; |
|
365 |
boolean startingIsSingle = false; |
|
366 |
|
|
367 |
Iterator<Map.Entry<Long, ScrambleStateBandagedCuboid>> it = map.entrySet().iterator(); |
|
368 |
|
|
369 |
while (it.hasNext()) |
|
179 |
if( excludedAxis!=1 ) |
|
370 | 180 |
{ |
371 |
Map.Entry<Long, ScrambleStateBandagedCuboid> entry = it.next(); |
|
372 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
373 |
|
|
374 |
if( value.numAxis()<2 ) |
|
375 |
{ |
|
376 |
long prunedID = value.getID(); |
|
377 |
|
|
378 |
if( prunedID!=startingID ) // do not remove the starting point, even if it does have only 1 axis |
|
379 |
{ |
|
380 |
it.remove(); |
|
381 |
pruned = true; |
|
382 |
} |
|
383 |
else |
|
181 |
for(int m=mStartY; m<mStartZ; m++) |
|
182 |
if( mMoves[m]!=null ) |
|
384 | 183 |
{ |
385 |
startingIsSingle = true; |
|
184 |
if( num==n ) return m; |
|
185 |
num++; |
|
386 | 186 |
} |
387 |
} |
|
388 | 187 |
} |
389 | 188 |
|
390 |
for (Map.Entry<Long, ScrambleStateBandagedCuboid> entry : map.entrySet() )
|
|
189 |
if( excludedAxis!=2 )
|
|
391 | 190 |
{ |
392 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
393 |
|
|
394 |
for(int m=0; m<NUM_MOVES; m++) |
|
395 |
{ |
|
396 |
long move = value.mMoves[m]; |
|
397 |
ScrambleStateBandagedCuboid tmp = findState(map,move); |
|
398 |
|
|
399 |
if( tmp==null || (startingIsSingle && move==startingID) ) |
|
400 |
{ |
|
401 |
value.mMoves[m]=INVALID_MOVE; |
|
402 |
} |
|
403 |
} |
|
404 |
} |
|
405 |
|
|
406 |
if( pruned ) pruneGraph(map,startingID); |
|
407 |
} |
|
408 |
|
|
409 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
410 |
|
|
411 |
private static void remapGraph(Map<Long, ScrambleStateBandagedCuboid> map) |
|
412 |
{ |
|
413 |
int id=0; |
|
414 |
|
|
415 |
for (Map.Entry<Long, ScrambleStateBandagedCuboid> entry : map.entrySet()) |
|
416 |
{ |
|
417 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
418 |
value.mID = id++; |
|
419 |
} |
|
420 |
|
|
421 |
for (Map.Entry<Long, ScrambleStateBandagedCuboid> entry : map.entrySet()) |
|
422 |
{ |
|
423 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
424 |
|
|
425 |
for(int m=0; m<NUM_MOVES; m++) |
|
426 |
{ |
|
427 |
long move = value.mMoves[m]; |
|
428 |
|
|
429 |
if( move!=INVALID_MOVE ) |
|
430 |
{ |
|
431 |
ScrambleStateBandagedCuboid tmp = map.get(move); |
|
432 |
value.mMoves[m] = tmp.mID; |
|
433 |
} |
|
434 |
} |
|
435 |
} |
|
436 |
} |
|
437 |
|
|
438 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
439 |
|
|
440 |
private static void computeDistance(Map<Long, ScrambleStateBandagedCuboid> map, long id, int distance) |
|
441 |
{ |
|
442 |
ScrambleStateBandagedCuboid state = findState(map,id); |
|
443 |
|
|
444 |
if( state==null ) |
|
445 |
{ |
|
446 |
android.util.Log.e("D", "error: "+id+" doesn't exist"); |
|
447 |
return; |
|
448 |
} |
|
449 |
|
|
450 |
if( state.mDistance<0 ) |
|
451 |
{ |
|
452 |
state.mDistance = distance; |
|
453 |
|
|
454 |
for(int i=0; i<NUM_MOVES; i++) |
|
455 |
{ |
|
456 |
long move = state.getMove(i); |
|
457 |
|
|
458 |
if( move!=INVALID_MOVE ) |
|
191 |
for(int m=mStartZ; m<mNumMoves; m++) |
|
192 |
if( mMoves[m]!=null ) |
|
459 | 193 |
{ |
460 |
computeDistance(map,move,distance+1); |
|
194 |
if( num==n ) return m; |
|
195 |
num++; |
|
461 | 196 |
} |
462 |
} |
|
463 | 197 |
} |
464 |
} |
|
465 |
|
|
466 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
467 |
|
|
468 |
private static void removeDisconnectedParts(Map<Long, ScrambleStateBandagedCuboid> map) |
|
469 |
{ |
|
470 |
Iterator<Map.Entry<Long, ScrambleStateBandagedCuboid>> it = map.entrySet().iterator(); |
|
471 |
|
|
472 |
while (it.hasNext()) |
|
473 |
{ |
|
474 |
Map.Entry<Long, ScrambleStateBandagedCuboid> entry = it.next(); |
|
475 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
476 |
if( value.mDistance<0 ) it.remove(); |
|
477 |
} |
|
478 |
} |
|
479 |
|
|
480 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
481 |
|
|
482 |
private static ScrambleStateBandagedCuboid findState(Map<Long, ScrambleStateBandagedCuboid> map, long id) |
|
483 |
{ |
|
484 |
return map.get(id); |
|
485 |
} |
|
486 |
|
|
487 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
488 |
|
|
489 |
private static String formatRet(String str, int row, int angle, long id) |
|
490 |
{ |
|
491 |
String ret = str.length()!=0 ? ",":""; |
|
492 |
|
|
493 |
ret += row; |
|
494 |
ret += angle<0 ? "," : ", "; |
|
495 |
ret += angle; |
|
496 |
|
|
497 |
if( id< 10 ) ret += (", "+id); |
|
498 |
else if( id<100 ) ret += (", " +id); |
|
499 |
else ret += ("," +id); |
|
500 |
|
|
501 |
return ret; |
|
502 |
} |
|
503 |
|
|
504 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
505 |
|
|
506 |
private static final int LENGTH = 28; |
|
507 | 198 |
|
508 |
private static String formatL(String input) |
|
509 |
{ |
|
510 |
int len = input.length(); |
|
511 |
String ret = input; |
|
512 |
for(int i=0 ;i<LENGTH-len; i++) ret += " "; |
|
513 |
return ret; |
|
199 |
return -1; |
|
514 | 200 |
} |
515 | 201 |
|
516 | 202 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
517 | 203 |
|
518 |
private static long[] createMoves(long id)
|
|
204 |
private ObjectSignature[] createMoves()
|
|
519 | 205 |
{ |
520 |
long[] ret = new long[NUM_MOVES];
|
|
206 |
ObjectSignature[] ret = new ObjectSignature[mNumMoves];
|
|
521 | 207 |
int index = 0; |
522 | 208 |
|
523 | 209 |
for(int axis=0; axis<3; axis++) |
524 |
for(int layer=0; layer<3; layer++) |
|
525 |
{ |
|
526 |
long x1 = turn(id,axis,layer); |
|
210 |
for(int layer=0; layer<mLayer[axis]; layer++) |
|
211 |
mIsUnblocked[axis][layer] = mSignature.isUnblockedFromLeft(axis,layer); |
|
527 | 212 |
|
528 |
if( x1!=INVALID_MOVE ) |
|
529 |
{ |
|
530 |
long x2 = turn(x1,axis,layer); |
|
531 |
long x3 = turn(x2,axis,layer); |
|
532 |
|
|
533 |
ret[index ] = x1; |
|
534 |
ret[index+1] = x2; |
|
535 |
ret[index+2] = x3; |
|
536 |
} |
|
537 |
else |
|
213 |
for(int axis=0; axis<3; axis++) |
|
214 |
if( mLayer[axis]>1 ) |
|
215 |
for(int turn=0; turn<mTurns[axis]; turn++) |
|
538 | 216 |
{ |
539 |
ret[index ] = INVALID_MOVE; |
|
540 |
ret[index+1] = INVALID_MOVE; |
|
541 |
ret[index+2] = INVALID_MOVE; |
|
217 |
boolean allLayersLocked = true; |
|
218 |
|
|
219 |
for(int layer=0; layer<mLayer[axis]; layer++) |
|
220 |
{ |
|
221 |
if( mIsUnblocked[axis][layer] ) |
|
222 |
{ |
|
223 |
if( layer>0 ) allLayersLocked = false; |
|
224 |
ret[index] = mSignature.turn(axis,layer,turn); |
|
225 |
} |
|
226 |
else |
|
227 |
{ |
|
228 |
ret[index] = ret[index-1].turn(axis,layer,turn); |
|
229 |
ret[index-1] = null; |
|
230 |
} |
|
231 |
|
|
232 |
index++; |
|
233 |
} |
|
234 |
|
|
235 |
if( allLayersLocked ) ret[index-1] = null; |
|
542 | 236 |
} |
543 | 237 |
|
544 |
index+=3; |
|
545 |
} |
|
546 |
|
|
547 | 238 |
return ret; |
548 | 239 |
} |
549 | 240 |
|
550 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
551 |
// Definition of the id: it's an 'Andreas signature' of a bandaged cube. |
|
552 |
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350 |
|
553 |
|
|
554 |
private static long turn(long id, int axis, int layer) |
|
555 |
{ |
|
556 |
switch(axis) |
|
557 |
{ |
|
558 |
case AXIS_X: switch(layer) |
|
559 |
{ |
|
560 |
case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 || |
|
561 |
getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 || |
|
562 |
getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ) return INVALID_MOVE; |
|
563 |
|
|
564 |
long x1 = cycle(id,9,14,46,41); |
|
565 |
long x2 = cycle(x1,4,35,51,20); |
|
566 |
return cycle(x2,17,25,38,30); |
|
567 |
|
|
568 |
case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 || |
|
569 |
getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 || |
|
570 |
getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 || |
|
571 |
getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 || |
|
572 |
getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 || |
|
573 |
getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1 ) return INVALID_MOVE; |
|
574 |
|
|
575 |
long x4 = cycle(id,8,13,45,40); |
|
576 |
long x5 = cycle(x4,3,34,50,19); |
|
577 |
return cycle(x5,16,24,37,29); |
|
578 |
|
|
579 |
case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 || |
|
580 |
getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 || |
|
581 |
getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1 ) return INVALID_MOVE; |
|
582 |
|
|
583 |
long x7 = cycle(id,7,12,44,39); |
|
584 |
long x8 = cycle(x7,2,33,49,18); |
|
585 |
return cycle(x8,15,23,36,28); |
|
586 |
} |
|
587 |
|
|
588 |
case AXIS_Y: switch(layer) |
|
589 |
{ |
|
590 |
case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 || |
|
591 |
getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 || |
|
592 |
getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ) return INVALID_MOVE; |
|
593 |
|
|
594 |
long y1 = cycle(id,1,9,10,2); |
|
595 |
long y2 = cycle(y1,0,4,11,7); |
|
596 |
return cycle(y2,3,6,8,5); |
|
597 |
|
|
598 |
case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 || |
|
599 |
getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 || |
|
600 |
getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 || |
|
601 |
getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 || |
|
602 |
getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 || |
|
603 |
getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1 ) return INVALID_MOVE; |
|
604 |
|
|
605 |
long y4 = cycle(id,21,25,32,28); |
|
606 |
long y5 = cycle(y4,22,30,31,23); |
|
607 |
return cycle(y5,24,27,29,26); |
|
608 |
|
|
609 |
case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 || |
|
610 |
getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 || |
|
611 |
getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1 ) return INVALID_MOVE; |
|
612 |
|
|
613 |
long y7 = cycle(id,42,46,53,49); |
|
614 |
long y8 = cycle(y7,43,51,52,44); |
|
615 |
return cycle(y8,45,48,50,47); |
|
616 |
} |
|
617 |
|
|
618 |
case AXIS_Z: switch(layer) |
|
619 |
{ |
|
620 |
case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 || |
|
621 |
getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 || |
|
622 |
getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ) return INVALID_MOVE; |
|
623 |
|
|
624 |
long z1 = cycle(id,10,20,53,39); |
|
625 |
long z2 = cycle(z1,11,41,52,18); |
|
626 |
return cycle(z2,19,32,40,31); |
|
627 |
|
|
628 |
case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 || |
|
629 |
getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 || |
|
630 |
getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 || |
|
631 |
getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 || |
|
632 |
getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 || |
|
633 |
getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1 ) return INVALID_MOVE; |
|
634 |
|
|
635 |
long z4 = cycle(id,5,17,48,36); |
|
636 |
long z5 = cycle(z4,6,38,47,15); |
|
637 |
return cycle(z5,16,27,37,26); |
|
638 |
|
|
639 |
case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 || |
|
640 |
getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 || |
|
641 |
getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1 ) return INVALID_MOVE; |
|
642 |
|
|
643 |
long z7 = cycle(id,0,14,43,33); |
|
644 |
long z8 = cycle(z7,1,35,42,12); |
|
645 |
return cycle(z8,13,22,34,21); |
|
646 |
} |
|
647 |
} |
|
648 |
|
|
649 |
return 0; |
|
650 |
} |
|
651 |
|
|
652 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
653 |
// bit b1 in place of b2 etc. |
|
654 |
|
|
655 |
private static long cycle(long id, int b1, int b2, int b3, int b4) |
|
656 |
{ |
|
657 |
long bit1 = getBit(id,b1); |
|
658 |
long bit2 = getBit(id,b2); |
|
659 |
long bit3 = getBit(id,b3); |
|
660 |
long bit4 = getBit(id,b4); |
|
661 |
|
|
662 |
long i1 = setBit(id,b2,bit1); |
|
663 |
long i2 = setBit(i1,b3,bit2); |
|
664 |
long i3 = setBit(i2,b4,bit3); |
|
665 |
return setBit(i3,b1,bit4); |
|
666 |
} |
|
667 |
|
|
668 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
669 |
|
|
670 |
private static long getBit(long id, int bit) |
|
671 |
{ |
|
672 |
return (id>>bit)&0x1; |
|
673 |
} |
|
674 |
|
|
675 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
676 |
|
|
677 |
private static long setBit(long id, int bit, long value) |
|
678 |
{ |
|
679 |
long old = getBit(id,bit); |
|
680 |
|
|
681 |
if( old!=value ) |
|
682 |
{ |
|
683 |
long diff = (1L<<bit); |
|
684 |
id += (value==0 ? -diff : diff); |
|
685 |
} |
|
686 |
|
|
687 |
return id; |
|
688 |
} |
|
689 |
|
|
690 | 241 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
691 | 242 |
|
692 | 243 |
private void printMoves() |
693 | 244 |
{ |
694 | 245 |
String moves = ""; |
695 | 246 |
|
696 |
for(int i=0; i<NUM_MOVES; i++)
|
|
247 |
for(int i=0; i<mNumMoves; i++)
|
|
697 | 248 |
{ |
698 |
moves += (" " + mMoves[i]);
|
|
249 |
moves += (mMoves[i]!=null ? " "+mMoves[i].getString() : " NULL");
|
|
699 | 250 |
} |
700 | 251 |
|
701 | 252 |
android.util.Log.e("D", moves); |
... | ... | |
721 | 272 |
|
722 | 273 |
return ret + "]"; |
723 | 274 |
} |
724 |
|
|
725 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
726 |
|
|
727 |
private static void printGraph(Map<Long, ScrambleStateBandagedCuboid> map) |
|
728 |
{ |
|
729 |
int num = map.size(); |
|
730 |
android.util.Log.e("D", "\n"+num+" states\n"); |
|
731 |
|
|
732 |
for (Map.Entry<Long, ScrambleStateBandagedCuboid> entry : map.entrySet()) |
|
733 |
{ |
|
734 |
ScrambleStateBandagedCuboid value = entry.getValue(); |
|
735 |
android.util.Log.e("D", value.formatMoves()); |
|
736 |
} |
|
737 |
} |
|
738 | 275 |
} |
Also available in: Unified diff
Introduce ObjectSignature that can incorporate 192-bit signatures (for 5x5x5 bandaged cubes).
ObjectScrambler does not fully work yet.