1 |
00947987
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
// Copyright 2023 Leszek Koltunski //
|
3 |
|
|
// //
|
4 |
|
|
// This file is part of Magic Cube. //
|
5 |
|
|
// //
|
6 |
|
|
// Magic Cube is proprietary software licensed under an EULA which you should have received //
|
7 |
|
|
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html //
|
8 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
9 |
|
|
|
10 |
|
|
package org.distorted.objectlib.tablebases;
|
11 |
|
|
|
12 |
884b702b
|
Leszek Koltunski
|
import android.content.res.Resources;
|
13 |
00947987
|
Leszek Koltunski
|
|
14 |
884b702b
|
Leszek Koltunski
|
import java.io.ByteArrayOutputStream;
|
15 |
|
|
import java.io.IOException;
|
16 |
|
|
import java.io.InputStream;
|
17 |
00947987
|
Leszek Koltunski
|
|
18 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
19 |
|
|
|
20 |
f079bf77
|
Leszek Koltunski
|
public abstract class TablebasesPruning extends TablebasesAbstract
|
21 |
884b702b
|
Leszek Koltunski
|
{
|
22 |
bdcb662f
|
Leszek Koltunski
|
private final int mGodsNumber;
|
23 |
|
|
|
24 |
884b702b
|
Leszek Koltunski
|
private boolean mInitialized;
|
25 |
f079bf77
|
Leszek Koltunski
|
private PruningTable[] mHighTables;
|
26 |
|
|
private PruningTable[] mMidTables;
|
27 |
bdcb662f
|
Leszek Koltunski
|
private int mLowestHigh, mHighestMid, mLowestMid;
|
28 |
00947987
|
Leszek Koltunski
|
|
29 |
15d1f6ad
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
30 |
|
|
|
31 |
f079bf77
|
Leszek Koltunski
|
abstract int[] getMidPruningLevels();
|
32 |
|
|
abstract int[] getHighPruningLevels();
|
33 |
|
|
abstract int getGodsNumber();
|
34 |
bdcb662f
|
Leszek Koltunski
|
abstract boolean moveCanProceed(int lastA, int lastL, int currA, int currL);
|
35 |
15d1f6ad
|
Leszek Koltunski
|
|
36 |
00947987
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
37 |
|
|
|
38 |
f079bf77
|
Leszek Koltunski
|
private PruningTable createPruningTable(Resources res, int id)
|
39 |
00947987
|
Leszek Koltunski
|
{
|
40 |
884b702b
|
Leszek Koltunski
|
InputStream stream = res.openRawResource(id);
|
41 |
|
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
42 |
00947987
|
Leszek Koltunski
|
|
43 |
884b702b
|
Leszek Koltunski
|
int nRead;
|
44 |
|
|
byte[] tmp = new byte[16384];
|
45 |
00947987
|
Leszek Koltunski
|
|
46 |
884b702b
|
Leszek Koltunski
|
try
|
47 |
00947987
|
Leszek Koltunski
|
{
|
48 |
884b702b
|
Leszek Koltunski
|
while ((nRead = stream.read(tmp, 0, tmp.length)) != -1)
|
49 |
00947987
|
Leszek Koltunski
|
{
|
50 |
884b702b
|
Leszek Koltunski
|
buffer.write(tmp, 0, nRead);
|
51 |
00947987
|
Leszek Koltunski
|
}
|
52 |
884b702b
|
Leszek Koltunski
|
stream.close();
|
53 |
|
|
byte[] data = buffer.toByteArray();
|
54 |
|
|
buffer.close();
|
55 |
f079bf77
|
Leszek Koltunski
|
return new PruningTable(data);
|
56 |
884b702b
|
Leszek Koltunski
|
}
|
57 |
|
|
catch(IOException ex)
|
58 |
00947987
|
Leszek Koltunski
|
{
|
59 |
884b702b
|
Leszek Koltunski
|
mInitialized = false;
|
60 |
f079bf77
|
Leszek Koltunski
|
return null;
|
61 |
00947987
|
Leszek Koltunski
|
}
|
62 |
884b702b
|
Leszek Koltunski
|
}
|
63 |
00947987
|
Leszek Koltunski
|
|
64 |
884b702b
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
65 |
00947987
|
Leszek Koltunski
|
|
66 |
f079bf77
|
Leszek Koltunski
|
public TablebasesPruning()
|
67 |
884b702b
|
Leszek Koltunski
|
{
|
68 |
|
|
super();
|
69 |
f079bf77
|
Leszek Koltunski
|
mGodsNumber = getGodsNumber();
|
70 |
7363eaa6
|
Leszek Koltunski
|
mInitialized = false;
|
71 |
00947987
|
Leszek Koltunski
|
}
|
72 |
|
|
|
73 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
74 |
|
|
|
75 |
f079bf77
|
Leszek Koltunski
|
public TablebasesPruning(Resources res, int[] midIDs, int[] highIDs)
|
76 |
00947987
|
Leszek Koltunski
|
{
|
77 |
884b702b
|
Leszek Koltunski
|
super();
|
78 |
|
|
|
79 |
f079bf77
|
Leszek Koltunski
|
int mid = midIDs !=null ? midIDs.length : 0;
|
80 |
|
|
int high= highIDs!=null ? highIDs.length : 0;
|
81 |
|
|
|
82 |
|
|
mMidTables = mid >0 ? new PruningTable[mid] : null;
|
83 |
|
|
mHighTables= high>0 ? new PruningTable[high]: null;
|
84 |
|
|
mGodsNumber = getGodsNumber();
|
85 |
884b702b
|
Leszek Koltunski
|
mInitialized = true;
|
86 |
|
|
|
87 |
f079bf77
|
Leszek Koltunski
|
for(int i=0; i<mid ; i++) mMidTables[i] = createPruningTable(res,midIDs[i] );
|
88 |
|
|
for(int i=0; i<high; i++) mHighTables[i]= createPruningTable(res,highIDs[i]);
|
89 |
bdcb662f
|
Leszek Koltunski
|
|
90 |
|
|
computeLowHigh();
|
91 |
00947987
|
Leszek Koltunski
|
}
|
92 |
|
|
|
93 |
15d1f6ad
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
94 |
|
|
|
95 |
|
|
public byte[][] getPacked()
|
96 |
|
|
{
|
97 |
7363eaa6
|
Leszek Koltunski
|
if( !mInitialized )
|
98 |
|
|
{
|
99 |
f079bf77
|
Leszek Koltunski
|
int[] midLevels = getMidPruningLevels();
|
100 |
|
|
int numMidLevels= midLevels!=null ? midLevels.length : 0;
|
101 |
|
|
int[] highLevels = getHighPruningLevels();
|
102 |
|
|
int numHighLevels= highLevels!=null ? highLevels.length : 0;
|
103 |
7363eaa6
|
Leszek Koltunski
|
int maxLevel = 0;
|
104 |
15d1f6ad
|
Leszek Koltunski
|
|
105 |
f079bf77
|
Leszek Koltunski
|
if( highLevels!=null )
|
106 |
|
|
{
|
107 |
|
|
for( int l : highLevels )
|
108 |
|
|
if( l>maxLevel ) maxLevel = l;
|
109 |
|
|
}
|
110 |
|
|
else
|
111 |
|
|
{
|
112 |
|
|
if( midLevels!=null )
|
113 |
|
|
for( int l : midLevels )
|
114 |
|
|
if( l>maxLevel ) maxLevel = l;
|
115 |
|
|
}
|
116 |
15d1f6ad
|
Leszek Koltunski
|
|
117 |
7363eaa6
|
Leszek Koltunski
|
createTablebase(maxLevel);
|
118 |
f079bf77
|
Leszek Koltunski
|
mMidTables = numMidLevels >0 ? new PruningTable[numMidLevels ] : null;
|
119 |
|
|
mHighTables= numHighLevels>0 ? new PruningTable[numHighLevels] : null;
|
120 |
15d1f6ad
|
Leszek Koltunski
|
|
121 |
f079bf77
|
Leszek Koltunski
|
for(int i=0; i<numMidLevels; i++)
|
122 |
|
|
mMidTables[i] = new PruningTable(mTablebase,midLevels[i]);
|
123 |
|
|
for(int i=0; i<numHighLevels; i++)
|
124 |
|
|
mHighTables[i] = new PruningTable(mTablebase,highLevels[i]);
|
125 |
15d1f6ad
|
Leszek Koltunski
|
|
126 |
bdcb662f
|
Leszek Koltunski
|
computeLowHigh();
|
127 |
|
|
|
128 |
7363eaa6
|
Leszek Koltunski
|
mInitialized = true;
|
129 |
15d1f6ad
|
Leszek Koltunski
|
}
|
130 |
|
|
|
131 |
f079bf77
|
Leszek Koltunski
|
int midNum = mMidTables !=null ? mMidTables.length : 0;
|
132 |
|
|
int highNum = mHighTables!=null ? mHighTables.length : 0;
|
133 |
|
|
byte[][] data = new byte[midNum+highNum][];
|
134 |
|
|
|
135 |
|
|
for(int i=0; i<midNum ; i++) data[i ] = mMidTables[i].getPacked();
|
136 |
|
|
for(int i=0; i<highNum; i++) data[i+midNum] = mHighTables[i].getPacked();
|
137 |
7363eaa6
|
Leszek Koltunski
|
|
138 |
15d1f6ad
|
Leszek Koltunski
|
return data;
|
139 |
|
|
}
|
140 |
|
|
|
141 |
00947987
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
142 |
|
|
|
143 |
bdcb662f
|
Leszek Koltunski
|
private void computeLowHigh()
|
144 |
|
|
{
|
145 |
|
|
mLowestHigh = mGodsNumber+1;
|
146 |
|
|
int numHigh = mHighTables==null ? 0 : mHighTables.length;
|
147 |
|
|
|
148 |
|
|
for( int i=0; i<numHigh; i++ )
|
149 |
|
|
{
|
150 |
|
|
int level = mHighTables[i].getLevel();
|
151 |
|
|
if( i==0 || level<mLowestHigh ) mLowestHigh=level;
|
152 |
|
|
}
|
153 |
|
|
|
154 |
|
|
mLowestMid = 0;
|
155 |
|
|
mHighestMid= 0;
|
156 |
|
|
int numMid = mMidTables==null ? 0 : mMidTables.length;
|
157 |
|
|
|
158 |
|
|
for( int i=0; i<numMid; i++ )
|
159 |
|
|
{
|
160 |
|
|
int level = mMidTables[i].getLevel();
|
161 |
|
|
if( i==0 || level<mLowestMid ) mLowestMid =level;
|
162 |
|
|
if( i==0 || level>mHighestMid ) mHighestMid=level;
|
163 |
|
|
}
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
167 |
|
|
|
168 |
|
|
public int traverseDownTable(int index, PruningTable[] tables, int tableIndex, int lastA, int lastR, int[] move, int[] tmpQuats)
|
169 |
|
|
{
|
170 |
|
|
int[] quats = getQuats(index);
|
171 |
|
|
int numQuats = quats.length;
|
172 |
|
|
|
173 |
|
|
move[0]=0;
|
174 |
|
|
move[1]=0;
|
175 |
|
|
move[2]=1;
|
176 |
|
|
move[3]=1;
|
177 |
|
|
|
178 |
|
|
for(int ax=0; ax<mNumAxis; ax++)
|
179 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
180 |
|
|
mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
|
181 |
|
|
|
182 |
|
|
for(int s=0; s<mScalingFactor; s++)
|
183 |
|
|
{
|
184 |
|
|
int ax = move[0];
|
185 |
|
|
int layer = move[1];
|
186 |
|
|
int quat = move[3];
|
187 |
|
|
|
188 |
|
|
if( mRotatable[ax][layer] && moveCanProceed(lastA,lastR,move[0],move[1]) )
|
189 |
|
|
{
|
190 |
|
|
int bitLayer = (1<<layer);
|
191 |
|
|
System.arraycopy(quats, 0, tmpQuats, 0, numQuats);
|
192 |
|
|
|
193 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
194 |
|
|
if( mRotRow[cubit][ax]==bitLayer )
|
195 |
|
|
{
|
196 |
|
|
int currQuat = tmpQuats[cubit];
|
197 |
|
|
int newQuat = getMultQuat(quat,currQuat);
|
198 |
|
|
tmpQuats[cubit] = newQuat;
|
199 |
|
|
}
|
200 |
|
|
|
201 |
|
|
int childIndex = getIndex(tmpQuats);
|
202 |
|
|
|
203 |
|
|
if( tableIndex>0 )
|
204 |
|
|
{
|
205 |
|
|
if( tables[tableIndex-1].contains(childIndex) ) return childIndex;
|
206 |
|
|
}
|
207 |
|
|
else if( !tables[0].contains(childIndex) )
|
208 |
|
|
{
|
209 |
|
|
if( tables.length<=1 || !tables[1].contains(childIndex) ) return childIndex;
|
210 |
|
|
}
|
211 |
|
|
}
|
212 |
|
|
|
213 |
|
|
getNextAxisLayerAngleQuat(move);
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
return -1;
|
217 |
|
|
}
|
218 |
|
|
|
219 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
220 |
|
|
|
221 |
|
|
private int traversePruningBlock(int[][] moves, PruningTable[] tables, int tableIndex, int index, int lastA, int lastR)
|
222 |
00947987
|
Leszek Koltunski
|
{
|
223 |
bdcb662f
|
Leszek Koltunski
|
int movesIndex = 1;
|
224 |
|
|
int[] move = moves[movesIndex];
|
225 |
|
|
int[] tmpQuats = new int[4];
|
226 |
|
|
|
227 |
|
|
do
|
228 |
|
|
{
|
229 |
|
|
index = traverseDownTable(index,tables,tableIndex,lastA,lastR,move,tmpQuats);
|
230 |
|
|
lastA = move[0];
|
231 |
|
|
lastR = move[1];
|
232 |
|
|
tableIndex--;
|
233 |
|
|
movesIndex++;
|
234 |
|
|
move = moves[movesIndex];
|
235 |
|
|
}
|
236 |
|
|
while( tableIndex>=0 );
|
237 |
|
|
|
238 |
|
|
return index;
|
239 |
|
|
}
|
240 |
|
|
|
241 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
242 |
|
|
// ret: [0][] --> (new index,new depth,?,?) ; [1...N-1][] --> moves. (or null if index not in High)
|
243 |
|
|
|
244 |
|
|
private int[][] traverseBlock(int index, PruningTable[] tables, int lastA, int lastR)
|
245 |
|
|
{
|
246 |
|
|
int num = (tables==null) ? 0 : tables.length;
|
247 |
|
|
int tableIndex = -1;
|
248 |
|
|
|
249 |
|
|
for( int i=0; i<num; i++ )
|
250 |
|
|
if( tables[i].contains(index) )
|
251 |
|
|
{
|
252 |
|
|
tableIndex = i;
|
253 |
|
|
break;
|
254 |
|
|
}
|
255 |
|
|
|
256 |
|
|
if( tableIndex<0 ) return null;
|
257 |
|
|
|
258 |
|
|
int[][] ret = new int[tableIndex+2][4];
|
259 |
|
|
ret[0][1] = tables[0].getLevel()-1;
|
260 |
|
|
ret[0][0] = traversePruningBlock(ret,tables,tableIndex,index,lastA, lastR);
|
261 |
|
|
|
262 |
|
|
return ret;
|
263 |
|
|
}
|
264 |
|
|
|
265 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
266 |
|
|
|
267 |
|
|
private int midTablesContain(int index)
|
268 |
|
|
{
|
269 |
|
|
int num = mMidTables.length;
|
270 |
|
|
|
271 |
|
|
for( int i=0; i<num; i++ )
|
272 |
|
|
if( mMidTables[i].contains(index) )
|
273 |
|
|
return i;
|
274 |
|
|
|
275 |
|
|
return -1;
|
276 |
|
|
}
|
277 |
|
|
|
278 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
279 |
|
|
|
280 |
|
|
private boolean jumpMidZeroRecursive(int index, int jump, int depth, int lastA, int lastR, int[][] solution)
|
281 |
|
|
{
|
282 |
|
|
int[] quats = getQuats(index);
|
283 |
|
|
int numQuats = quats.length;
|
284 |
|
|
int[] move = solution[depth];
|
285 |
|
|
int[] tmp = new int[mNumCubits];
|
286 |
|
|
|
287 |
|
|
move[0]=0;
|
288 |
|
|
move[1]=0;
|
289 |
|
|
move[2]=1;
|
290 |
|
|
move[3]=1;
|
291 |
|
|
|
292 |
|
|
for(int ax=0; ax<mNumAxis; ax++)
|
293 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
294 |
|
|
mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
|
295 |
|
|
|
296 |
|
|
for(int s=0; s<mScalingFactor; s++)
|
297 |
|
|
{
|
298 |
|
|
int ax = move[0];
|
299 |
|
|
int layer = move[1];
|
300 |
|
|
int quat = move[3];
|
301 |
|
|
|
302 |
|
|
if( mRotatable[ax][layer] && moveCanProceed(lastA,lastR,ax,layer) )
|
303 |
|
|
{
|
304 |
|
|
int bitLayer = (1<<layer);
|
305 |
|
|
System.arraycopy(quats, 0, tmp, 0, numQuats);
|
306 |
|
|
|
307 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
308 |
|
|
if( mRotRow[cubit][ax]==bitLayer )
|
309 |
|
|
{
|
310 |
|
|
int currQuat = tmp[cubit];
|
311 |
|
|
int newQuat = getMultQuat(quat,currQuat);
|
312 |
|
|
tmp[cubit] = newQuat;
|
313 |
|
|
}
|
314 |
|
|
|
315 |
|
|
int childIndex = getIndex(tmp);
|
316 |
|
|
|
317 |
|
|
if( childIndex==0 )
|
318 |
|
|
{
|
319 |
|
|
solution[0][0] = childIndex;
|
320 |
|
|
solution[0][1] = 0;
|
321 |
|
|
return true;
|
322 |
|
|
}
|
323 |
|
|
|
324 |
|
|
int containingTable = midTablesContain(childIndex);
|
325 |
|
|
|
326 |
|
|
if( containingTable>=0 )
|
327 |
|
|
{
|
328 |
|
|
solution[0][0] = childIndex;
|
329 |
|
|
solution[0][1] = mMidTables[containingTable].getLevel();
|
330 |
|
|
return true;
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
if( jump>1 && jumpMidZeroRecursive(childIndex, jump-1, depth+1, ax, layer, solution) )
|
334 |
|
|
{
|
335 |
|
|
return true;
|
336 |
|
|
}
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
getNextAxisLayerAngleQuat(move);
|
340 |
|
|
}
|
341 |
|
|
|
342 |
|
|
return false;
|
343 |
|
|
}
|
344 |
|
|
|
345 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
346 |
|
|
// ret: [0][] --> (?,old depth,?,?) ; [1...N-1][] --> moves.
|
347 |
|
|
|
348 |
|
|
private int[][] jumpToMidOrZero(int index, int maxJump, int lastA, int lastR)
|
349 |
|
|
{
|
350 |
|
|
int[][] solution = new int[maxJump+1][4];
|
351 |
|
|
|
352 |
|
|
for(int i=1; i<maxJump; i++)
|
353 |
|
|
if( jumpMidZeroRecursive(index,i,1,lastA,lastR,solution) )
|
354 |
|
|
return solution;
|
355 |
|
|
|
356 |
|
|
return null;
|
357 |
|
|
}
|
358 |
|
|
|
359 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
360 |
|
|
|
361 |
|
|
private boolean jumpZeroRecursive(int index, int jump, int depth, int lastA, int lastR, int[][] solution)
|
362 |
|
|
{
|
363 |
|
|
int[] quats = getQuats(index);
|
364 |
|
|
int numQuats = quats.length;
|
365 |
|
|
int[] move = solution[depth];
|
366 |
|
|
int[] tmp = new int[mNumCubits];
|
367 |
|
|
|
368 |
|
|
android.util.Log.e("D", "trying 0rec: index="+index);
|
369 |
|
|
|
370 |
|
|
move[0]=0;
|
371 |
|
|
move[1]=0;
|
372 |
|
|
move[2]=1;
|
373 |
|
|
move[3]=1;
|
374 |
|
|
|
375 |
|
|
for(int ax=0; ax<mNumAxis; ax++)
|
376 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
377 |
|
|
mRotRow[cubit][ax] = computeRow(mPosition[cubit],quats[cubit],ax);
|
378 |
|
|
|
379 |
|
|
for(int s=0; s<mScalingFactor; s++)
|
380 |
|
|
{
|
381 |
|
|
int ax = move[0];
|
382 |
|
|
int layer = move[1];
|
383 |
|
|
int quat = move[3];
|
384 |
|
|
|
385 |
|
|
if( mRotatable[ax][layer] && moveCanProceed(lastA,lastR,move[0],move[1]) )
|
386 |
|
|
{
|
387 |
|
|
int bitLayer = (1<<layer);
|
388 |
|
|
System.arraycopy(quats, 0, tmp, 0, numQuats);
|
389 |
|
|
|
390 |
|
|
for(int cubit=0; cubit<mNumCubits; cubit++)
|
391 |
|
|
if( mRotRow[cubit][ax]==bitLayer )
|
392 |
|
|
{
|
393 |
|
|
int currQuat = tmp[cubit];
|
394 |
|
|
int newQuat = getMultQuat(quat,currQuat);
|
395 |
|
|
tmp[cubit] = newQuat;
|
396 |
|
|
}
|
397 |
|
|
|
398 |
|
|
int childIndex = getIndex(tmp);
|
399 |
|
|
if( childIndex==0 )
|
400 |
|
|
{
|
401 |
|
|
android.util.Log.e("D", "END: ax="+ax+" layer="+layer+" angle: "+move[2]);
|
402 |
|
|
return true;
|
403 |
|
|
}
|
404 |
|
|
if( jump>1 && jumpZeroRecursive(childIndex, jump-1, depth+1, ax, layer, solution) )
|
405 |
|
|
{
|
406 |
|
|
android.util.Log.e("D", "REC: ax="+ax+" layer="+layer+" angle: "+move[2]);
|
407 |
|
|
return true;
|
408 |
|
|
}
|
409 |
|
|
}
|
410 |
|
|
|
411 |
|
|
getNextAxisLayerAngleQuat(move);
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
return false;
|
415 |
|
|
}
|
416 |
|
|
|
417 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
418 |
|
|
// ret: [0][] --> (?,old depth,?,?) ; [1...N-1][] --> moves.
|
419 |
|
|
|
420 |
|
|
private int[][] jumpToZero(int index, int maxJump, int lastA, int lastR)
|
421 |
|
|
{
|
422 |
|
|
int[][] solution = new int[maxJump+1][4];
|
423 |
|
|
|
424 |
|
|
for(int i=1; i<maxJump; i++)
|
425 |
|
|
if( jumpZeroRecursive(index,i,1,lastA,lastR,solution) )
|
426 |
|
|
return solution;
|
427 |
|
|
|
428 |
00947987
|
Leszek Koltunski
|
return null;
|
429 |
|
|
}
|
430 |
bdcb662f
|
Leszek Koltunski
|
|
431 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
432 |
|
|
|
433 |
|
|
private int[][] concatenateMoves(int[][] high, int[][] jump1, int[][] mid, int[][] jump2)
|
434 |
|
|
{
|
435 |
|
|
int len1 = high ==null ? 0 : high.length-1;
|
436 |
|
|
int len2 = jump1==null ? 0 : jump1[0][1];
|
437 |
|
|
int len3 = mid ==null ? 0 : mid.length-1;
|
438 |
|
|
int len4 = jump2==null ? 0 : jump2[0][1];
|
439 |
|
|
|
440 |
|
|
int[][] moves = new int[len1+len2+len3+len4][];
|
441 |
|
|
int index = 0;
|
442 |
|
|
|
443 |
|
|
for(int i=0; i<len1; i++) moves[index++] = high[i+1];
|
444 |
|
|
for(int i=0; i<len2; i++) moves[index++] = jump1[i+1];
|
445 |
|
|
for(int i=0; i<len3; i++) moves[index++] = mid[i+1];
|
446 |
|
|
for(int i=0; i<len4; i++) moves[index++] = jump2[i+1];
|
447 |
|
|
|
448 |
|
|
convertMoves(moves);
|
449 |
|
|
|
450 |
|
|
return moves;
|
451 |
|
|
}
|
452 |
|
|
|
453 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
454 |
|
|
|
455 |
|
|
public int[][] solution(int index, int[] extra)
|
456 |
|
|
{
|
457 |
|
|
if( index==0 ) return null;
|
458 |
|
|
int lastA=-1, lastR=0;
|
459 |
|
|
int[][] highMoves = traverseBlock(index,mHighTables,lastA,lastR);
|
460 |
|
|
|
461 |
|
|
if( highMoves!=null )
|
462 |
|
|
{
|
463 |
|
|
index = highMoves[0][0];
|
464 |
|
|
int len = highMoves.length;
|
465 |
|
|
lastA = highMoves[len-1][0];
|
466 |
|
|
lastR = highMoves[len-1][1];
|
467 |
|
|
}
|
468 |
|
|
|
469 |
|
|
int maxJump = Math.max(mLowestHigh-1-mHighestMid,mLowestMid/2);
|
470 |
|
|
int[][] jump1Moves = jumpToMidOrZero(index,maxJump,lastA,lastR);
|
471 |
|
|
|
472 |
|
|
if( jump1Moves!=null )
|
473 |
|
|
{
|
474 |
|
|
if( jump1Moves[0][0]==0 )
|
475 |
|
|
{
|
476 |
|
|
return concatenateMoves(null,null,null,jump1Moves);
|
477 |
|
|
}
|
478 |
|
|
if( jump1Moves[0][1]==mLowestMid )
|
479 |
|
|
{
|
480 |
|
|
int[][] jump2Moves = jumpToZero(index,mLowestMid-1,-1,0);
|
481 |
|
|
if( jump2Moves==null ) throw new RuntimeException("1 error jumping to 0");
|
482 |
|
|
return concatenateMoves(null,null,null,jump2Moves);
|
483 |
|
|
}
|
484 |
|
|
|
485 |
|
|
index = jump1Moves[0][0];
|
486 |
|
|
int len = jump1Moves.length;
|
487 |
|
|
lastA = jump1Moves[len-1][0];
|
488 |
|
|
lastR = jump1Moves[len-1][1];
|
489 |
|
|
}
|
490 |
|
|
|
491 |
|
|
int[][] midMoves = traverseBlock(index,mMidTables,lastA,lastR);
|
492 |
|
|
if( midMoves!=null )
|
493 |
|
|
{
|
494 |
|
|
index = midMoves[0][0];
|
495 |
|
|
int len = midMoves.length;
|
496 |
|
|
lastA = midMoves[len-1][0];
|
497 |
|
|
lastR = midMoves[len-1][1];
|
498 |
|
|
}
|
499 |
|
|
else throw new RuntimeException("error traversing mid Tables");
|
500 |
|
|
|
501 |
|
|
int[][] jump2Moves = jumpToZero(index,mLowestMid-1,lastA,lastR);
|
502 |
|
|
if( jump2Moves==null ) throw new RuntimeException("2 error jumping to 0");
|
503 |
|
|
return concatenateMoves(highMoves,jump1Moves,midMoves,jump2Moves);
|
504 |
|
|
}
|
505 |
00947987
|
Leszek Koltunski
|
}
|