Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / cube3 / SolverSearch.java @ 68191e7d

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2008 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.solvers.cube3;
21

    
22
import android.content.res.Resources;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25

    
26
public class SolverSearch
27
{
28
	static int mNumMoves = 0;
29
	
30
	static int[] ax      = new int[31]; // The axis of the move
31
	static int[] po      = new int[31]; // The power of the move
32

    
33
	static int[] flip    = new int[31]; // phase1 coordinates
34
	static int[] twist   = new int[31];
35
	static int[] slice   = new int[31];
36

    
37
	static int[] parity  = new int[31]; // phase2 coordinates
38
	static int[] URFtoDLF= new int[31];
39
	static int[] FRtoBR  = new int[31];
40
	static int[] URtoUL  = new int[31];
41
	static int[] UBtoDF  = new int[31];
42
	static int[] URtoDF  = new int[31];
43

    
44
	static int[] minDistPhase1 = new int[31]; // IDA * distance to goal estimations
45
	static int[] minDistPhase2 = new int[31];
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
	static String solutionToString(int length) 
50
	  {
51
		StringBuilder s = new StringBuilder();
52
		
53
		for( int i=0; i<length; i++)
54
		  {
55
			switch(ax[i])
56
			  {
57
			  case 0: switch(po[i])
58
			            {
59
			            case 1: s.append(" 548"); break;
60
			            case 2: s.append(" 804"); break;
61
			            case 3: s.append(" 292"); break;
62
			            }
63
				        break;
64
			  case 1: switch(po[i])
65
	                {
66
	                case 1: s.append(" 516"); break;
67
	                case 2: s.append(" 772"); break;
68
	                case 3: s.append(" 260"); break;
69
	                }
70
				        break;
71
		  	case 2: switch(po[i])
72
                  {
73
                  case 1: s.append(" 580"); break;
74
                  case 2: s.append(" 836"); break;
75
                  case 3: s.append(" 324"); break;
76
                  }
77
				        break;
78
		  	case 3: switch(po[i])
79
                  {
80
                  case 1: s.append(" 289"); break;
81
                  case 2: s.append(" 033"); break;
82
                  case 3: s.append(" 545"); break;
83
                  }
84
				        break;
85
			  case 4: switch(po[i])
86
                  {
87
                  case 1: s.append(" 257"); break;
88
                  case 2: s.append(" 001"); break;
89
                  case 3: s.append(" 513"); break;
90
                  }
91
				        break;
92
			  case 5: switch(po[i])
93
                  {
94
                  case 1: s.append(" 321"); break;
95
                  case 2: s.append(" 065"); break;
96
                  case 3: s.append(" 577"); break;
97
                  }
98
				        break;
99
			  }
100
		  }
101
		return s.toString();
102
	}
103

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

    
106
	public static void prepare(Resources res)
107
	  {
108
	  SolverCoordCube.initialize(res,0);
109
    SolverCoordCube.initialize(res,1);
110
		SolverCoordCube.initialize(res,2);
111
		SolverCoordCube.initialize(res,3);
112
		SolverCoordCube.initialize(res,4);
113
		SolverCoordCube.initialize(res,5);
114
		SolverCoordCube.initialize(res,6);
115
		SolverCoordCube.initialize(res,7);
116
		SolverCoordCube.initialize(res,8);
117
		SolverCoordCube.initialize(res,9);
118
		SolverCoordCube.initialize(res,10);
119
		SolverCoordCube.initialize(res,11);
120
	  }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123
/**
124
 * Computes the solver string for a given cube.
125
 *
126
 * @param facelets
127
 *          is the cube definition string, see {@link SolverFacelet} for the format.
128
 *
129
 * @param maxDepth
130
 *          defines the maximal allowed maneuver length. For random cubes, a maxDepth of 21 usually
131
 *          will return a solution in less than 0.5 seconds. With a maxDepth of 20 it takes a few
132
 *          seconds on average to find a solution, but it may take much longer for specific cubes.
133
 *
134
 *@param timeOut
135
 *          defines the maximum computing time of the method in seconds. If it does not return with
136
 *          a solution, it returns with an error code.
137
 * @return The solution string or an error code:
138
 *         Error 1: There is not exactly one facelet of each color
139
 *         Error 2: Not all 12 edges exist exactly once
140
 *         Error 3: Flip error: One edge has to be flipped
141
 *         Error 4: Not all corners exist exactly once
142
 *         Error 5: Twist error: One corner has to be twisted
143
 *         Error 6: Parity error: Two corners or two edges have to be exchanged
144
 *         Error 7: No solution exists for the given maxDepth
145
 *         Error 8: Timeout, no solution within given time
146
 */
147

    
148
	public static String solution(String facelets, int maxDepth, long timeOut) 
149
	  {
150
		int s;
151
		int[] count = new int[6];
152

    
153
		try
154
		  {
155
			for( int i=0; i<54; i++)
156
				count[SolverColor.toInt(facelets.substring(i,i+1))]++;
157
		  }
158
		catch (Exception e)
159
		  {
160
		  android.util.Log.d("error", "1");
161
			return "Error 1";
162
		  }
163

    
164
		for( int i=0; i<6; i++)
165
			if (count[i] != 9)
166
			  {
167
			  android.util.Log.d("error", "2");
168
				return "Error 1";
169
				}
170

    
171
		SolverFaceCube fc = new SolverFaceCube(facelets);
172
		SolverCubieCube cc = fc.toCubieCube();
173
		if ((s = cc.verify()) != 0)
174
		  {
175
		  android.util.Log.d("error", "3");
176
			return "Error " + Math.abs(s);
177
			}
178

    
179
		SolverCoordCube c = new SolverCoordCube(cc);
180

    
181
		po[0] = 0;
182
		ax[0] = 0;
183
		flip[0] = c.flip;
184
		twist[0] = c.twist;
185
		parity[0] = c.parity;
186
		slice[0] = c.FRtoBR / 24;
187
		URFtoDLF[0] = c.URFtoDLF;
188
		FRtoBR[0] = c.FRtoBR;
189
		URtoUL[0] = c.URtoUL;
190
		UBtoDF[0] = c.UBtoDF;
191

    
192
		minDistPhase1[1] = 1;// else failure for depth=1, n=0
193
		int mv, n=0;
194
		boolean busy = false;
195
		int depthPhase1 = 1;
196

    
197
		long tStart = System.currentTimeMillis();
198

    
199
		do
200
		  {
201
			do
202
			  {
203
				if( (depthPhase1-n > minDistPhase1[n+1]) && !busy)
204
				  {
205
					if (ax[n]==0 || ax[n]==3)// Initialize next move
206
						ax[++n] = 1;
207
					else
208
						ax[++n] = 0;
209
					po[n] = 1;
210
				  }
211
				else if (++po[n] > 3)
212
				  {
213
					do
214
					  { // increment axis
215
						if (++ax[n] > 5)
216
						  {
217
							if (System.currentTimeMillis() - tStart > timeOut << 10)
218
								return "Error 8";
219

    
220
							if (n==0)
221
							  {
222
								if (depthPhase1 >= maxDepth)
223
									return "Error 7";
224
								else
225
								  {
226
									depthPhase1++;
227
									ax[n] = 0;
228
									po[n] = 1;
229
									busy = false;
230
									break;
231
								  }
232
							  }
233
							else
234
							  {
235
								n--;
236
								busy = true;
237
								break;
238
							  }
239
						  }
240
						else
241
						  {
242
							po[n] = 1;
243
							busy = false;
244
						  }
245
					  }
246
					while (n != 0 && (ax[n - 1] == ax[n] || ax[n - 1] - 3 == ax[n]));
247
				  }
248
				else
249
					busy = false;
250
			  }
251
			while (busy);
252

    
253
			// compute new coordinates and new minDistPhase1. If minDistPhase1 =0, the H subgroup is reached
254
			mv = 3*ax[n]+po[n]-1;
255
			flip [n+1] = SolverCoordCube.getFlipMove(flip[n],mv);
256
			twist[n+1] = SolverCoordCube.getTwistMove(twist[n],mv);
257
			slice[n+1] = SolverCoordCube.getFRtoBR_Move(slice[n] * 24,mv) / 24;
258
			minDistPhase1[n+1] = Math.max(SolverCoordCube.getPruning(SolverCoordCube.Slice_Flip_Prun, SolverCoordCube.N_SLICE1 * flip[n+1]
259
					+ slice[n+1]), SolverCoordCube.getPruning(SolverCoordCube.Slice_Twist_Prun, SolverCoordCube.N_SLICE1 * twist[n+1]
260
					+ slice[n+1]));
261

    
262
			if (minDistPhase1[n+1]==0 && n >= depthPhase1 - 5)
263
			  {
264
				minDistPhase1[n+1] = 10;// instead of 10 any value >5 is possible
265
				if (n==depthPhase1-1 && (s = totalDepth(depthPhase1, maxDepth)) >= 0)
266
				  {
267
					if (s==depthPhase1 || (ax[depthPhase1-1] != ax[depthPhase1] && ax[depthPhase1-1] != ax[depthPhase1]+3))
268
					  {
269
						mNumMoves = s;
270
						return solutionToString(s);
271
					  }
272
				  }
273
			  }
274
		  }
275
		while (true);
276
	  }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279
// Apply phase2 of algorithm and return the combined phase1 and phase2 depth. In phase2, only the moves
280
// U,D,R2,F2,L2 and B2 are allowed.
281

    
282
	static int totalDepth(int depthPhase1, int maxDepth)
283
	  {
284
		int mv, d1, d2;
285
		int maxDepthPhase2 = Math.min(10,maxDepth-depthPhase1);// Allow only max 10 moves in phase2
286
		for( int i=0; i<depthPhase1; i++)
287
		  {
288
			mv = 3*ax[i]+po[i]-1;
289
			URFtoDLF[i+1] = SolverCoordCube.getURFtoDLF_Move(URFtoDLF[i],mv);
290
			FRtoBR  [i+1] = SolverCoordCube.getFRtoBR_Move(FRtoBR[i],mv);
291
			parity  [i+1] = SolverCoordCube.parityMove[parity[i]][mv];
292
		  }
293

    
294
		if( (d1 = SolverCoordCube.getPruning(SolverCoordCube.Slice_URFtoDLF_Parity_Prun,
295
				(SolverCoordCube.N_SLICE2 * URFtoDLF[depthPhase1] + FRtoBR[depthPhase1]) * 2 + parity[depthPhase1])) > maxDepthPhase2)
296
			return -1;
297

    
298
		for( int i=0; i<depthPhase1; i++)
299
		  {
300
			mv = 3 * ax[i] + po[i] - 1;
301
			URtoUL[i + 1] = SolverCoordCube.getURtoUL_Move(URtoUL[i],mv);
302
			UBtoDF[i + 1] = SolverCoordCube.getUBtoDF_Move(UBtoDF[i],mv);
303
		  }
304

    
305
		URtoDF[depthPhase1] = SolverCoordCube.getMergeURtoULandUBtoDF(URtoUL[depthPhase1],UBtoDF[depthPhase1]);
306

    
307
		if ((d2 = SolverCoordCube.getPruning(SolverCoordCube.Slice_URtoDF_Parity_Prun,
308
				(SolverCoordCube.N_SLICE2 * URtoDF[depthPhase1] + FRtoBR[depthPhase1]) * 2 + parity[depthPhase1])) > maxDepthPhase2)
309
			return -1;
310

    
311
		if ((minDistPhase2[depthPhase1] = Math.max(d1, d2)) == 0)// already solved
312
			return depthPhase1;
313

    
314
		// now set up search
315
		int depthPhase2 = 1;
316
		int n = depthPhase1;
317
		boolean busy = false;
318
		po[depthPhase1] = 0;
319
		ax[depthPhase1] = 0;
320
		minDistPhase2[n + 1] = 1; // else failure for depthPhase2=1, n=0
321
		// end initialization
322

    
323
		do
324
		  {
325
			do
326
			  {
327
				if ((depthPhase1 + depthPhase2 - n > minDistPhase2[n + 1]) && !busy)
328
				  {
329
					if (ax[n] == 0 || ax[n] == 3)// Initialize next move
330
					  {
331
						ax[++n] = 1;
332
						po[n] = 2;
333
					  }
334
					else
335
					  {
336
						ax[++n] = 0;
337
						po[n] = 1;
338
					  }
339
				  }
340
				else if ((ax[n] == 0 || ax[n] == 3) ? (++po[n] > 3) : ((po[n] = po[n] + 2) > 3))
341
				  {
342
					do
343
					  {
344
						if (++ax[n] > 5)
345
						  {
346
							if (n == depthPhase1)
347
							  {
348
								if (depthPhase2 >= maxDepthPhase2)
349
									return -1;
350
								else
351
								  {
352
									depthPhase2++;
353
									ax[n] = 0;
354
									po[n] = 1;
355
									busy = false;
356
									break;
357
								  }
358
							  }
359
							else
360
							  {
361
								n--;
362
								busy = true;
363
								break;
364
							  }
365
						  }
366
						else
367
						  {
368
							if (ax[n]==0 || ax[n]==3)
369
								po[n] = 1;
370
							else
371
								po[n] = 2;
372
							busy = false;
373
						  }
374
					  }
375
					while (n != depthPhase1 && (ax[n - 1] == ax[n] || ax[n - 1] - 3 == ax[n]));
376
				  }
377
				else
378
					busy = false;
379
			  }
380
			while (busy);
381

    
382
			// compute new coordinates and new minDist
383
			mv = 3*ax[n]+po[n]-1;
384

    
385
			URFtoDLF[n+1] = SolverCoordCube.getURFtoDLF_Move(URFtoDLF[n],mv);
386
			FRtoBR  [n+1] = SolverCoordCube.getFRtoBR_Move(FRtoBR[n],mv);
387
			parity  [n+1] = SolverCoordCube.parityMove[parity[n]][mv];
388
			URtoDF  [n+1] = SolverCoordCube.getURtoDF_Move(URtoDF[n],mv);
389

    
390
			minDistPhase2[n+1] = Math.max(SolverCoordCube.getPruning(SolverCoordCube.Slice_URtoDF_Parity_Prun, (SolverCoordCube.N_SLICE2
391
					* URtoDF[n+1] + FRtoBR[n+1])
392
					* 2 + parity[n+1]), SolverCoordCube.getPruning(SolverCoordCube.Slice_URFtoDLF_Parity_Prun, (SolverCoordCube.N_SLICE2
393
					* URFtoDLF[n+1] + FRtoBR[n+1])
394
					* 2 + parity[n+1]));
395
		  }
396
		while (minDistPhase2[n + 1] != 0);
397

    
398
		return depthPhase1 + depthPhase2;
399
	  }
400
}
(8-8/8)