Revision 6bd1dc64
Added by Leszek Koltunski 9 months ago
src/main/java/org/distorted/objectlib/algphases/Phase.java | ||
---|---|---|
11 | 11 |
|
12 | 12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
13 | 13 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
14 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
14 | 15 |
|
15 | 16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
16 | 17 |
|
... | ... | |
20 | 21 |
|
21 | 22 |
protected int[][] mCubitGroups; |
22 | 23 |
protected int mNumGroups; |
24 |
protected int mNumCubitsInThisPhase; |
|
23 | 25 |
protected int mNumCubits; |
24 |
protected int[][] mEndQuats; |
|
26 |
protected TargetQuats mTargetQuats; |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
Phase(SolvedObject object) |
|
31 |
{ |
|
32 |
float[][] pos = object.getCubitPositions(); |
|
33 |
mNumCubits = pos.length; |
|
34 |
} |
|
25 | 35 |
|
26 | 36 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
27 | 37 |
|
... | ... | |
41 | 51 |
public int whichSubPhase(int cubit) |
42 | 52 |
{ |
43 | 53 |
for(int g=0; g<mNumGroups; g++) |
44 |
for( int j : mCubitGroups[g])
|
|
54 |
for(int j : mCubitGroups[g]) |
|
45 | 55 |
if( cubit==j ) return g; |
46 | 56 |
|
47 | 57 |
return -1; |
... | ... | |
49 | 59 |
|
50 | 60 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
51 | 61 |
|
52 |
public int[] endQuatIndices(SolvedObject object, int cubitQuat, int cubit)
|
|
62 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
53 | 63 |
{ |
54 | 64 |
return INDICES; |
55 | 65 |
} |
56 | 66 |
|
57 | 67 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
58 | 68 |
|
59 |
public void setEndQuats(int[][] endquats)
|
|
69 |
public void setTargetQuats(SolvedObject object, boolean[] inPreviousPhases)
|
|
60 | 70 |
{ |
61 |
mEndQuats = endquats; |
|
62 |
} |
|
71 |
int len = inPreviousPhases.length; |
|
63 | 72 |
|
64 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
73 |
int[][] target = new int[len][];
|
|
65 | 74 |
|
66 |
public int[][] getEndQuats() |
|
67 |
{ |
|
68 |
return mEndQuats; |
|
75 |
for(int c=0; c<len; c++) |
|
76 |
{ |
|
77 |
if( inPreviousPhases[c] ) target[c] = INDICES; |
|
78 |
else if( contains(c) ) target[c] = endQuatIndices(object,c); |
|
79 |
else target[c] = null; |
|
80 |
} |
|
81 |
|
|
82 |
mTargetQuats = new TargetQuats(target); |
|
69 | 83 |
} |
70 | 84 |
|
71 | 85 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicOrie1.java | ||
---|---|---|
23 | 23 |
|
24 | 24 |
public PhaseCyclicOrie1(SolvedObject object, int cubit, int quat) |
25 | 25 |
{ |
26 |
super(object); |
|
27 |
|
|
26 | 28 |
Static4D[] objectQuats = object.getQuats(); |
27 | 29 |
Static4D q = objectQuats[quat]; |
28 | 30 |
double alpha = 2*Math.acos(q.get3()); |
29 | 31 |
double numTurns = 2*Math.PI / alpha; |
30 |
mNumCubits = (int)(numTurns+0.5f); |
|
32 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f);
|
|
31 | 33 |
|
32 |
mCubitGroups = new int[1][mNumCubits]; |
|
34 |
mCubitGroups = new int[1][mNumCubitsInThisPhase];
|
|
33 | 35 |
mNumGroups = 1; |
34 | 36 |
mCyclicQuat = quat; |
35 | 37 |
|
... | ... | |
43 | 45 |
|
44 | 46 |
mCubitGroups[0][0] = cubit; |
45 | 47 |
|
46 |
for(int c=1; c<mNumCubits; c++) |
|
48 |
for(int c=1; c<mNumCubitsInThisPhase; c++)
|
|
47 | 49 |
{ |
48 | 50 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
49 | 51 |
x = tmp[0]; |
... | ... | |
84 | 86 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
85 | 87 |
|
86 | 88 |
@Override |
87 |
public int[] endQuatIndices(SolvedObject object, int cubitQuat, int cubit)
|
|
89 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
88 | 90 |
{ |
89 |
int[] retQuats = new int[mNumCubits]; |
|
91 |
int[] retQuats = new int[mNumCubitsInThisPhase];
|
|
90 | 92 |
retQuats[0] = 0; |
91 | 93 |
retQuats[1] = mCyclicQuat; |
92 | 94 |
|
93 |
for(int i=2; i<mNumCubits; i++) |
|
95 |
for(int i=2; i<mNumCubitsInThisPhase; i++)
|
|
94 | 96 |
{ |
95 | 97 |
retQuats[i] = object.getMultQuat(mCyclicQuat,retQuats[i-1]); |
96 | 98 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicOrie2.java | ||
---|---|---|
19 | 19 |
{ |
20 | 20 |
public PhaseCyclicOrie2(SolvedObject object, int cubit, int quat) |
21 | 21 |
{ |
22 |
super(object); |
|
23 |
|
|
22 | 24 |
Static4D[] objectQuats = object.getQuats(); |
23 | 25 |
Static4D q = objectQuats[quat]; |
24 | 26 |
double alpha = 2*Math.acos(q.get3()); |
25 | 27 |
double numTurns = 2*Math.PI / alpha; |
26 |
mNumCubits = (int)(numTurns+0.5f); |
|
28 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f);
|
|
27 | 29 |
|
28 |
mCubitGroups = new int[1][mNumCubits]; |
|
30 |
mCubitGroups = new int[1][mNumCubitsInThisPhase];
|
|
29 | 31 |
mNumGroups = 1; |
30 | 32 |
|
31 | 33 |
float[][] positions = object.getCubitPositions(); |
... | ... | |
38 | 40 |
|
39 | 41 |
mCubitGroups[0][0] = cubit; |
40 | 42 |
|
41 |
for(int c=1; c<mNumCubits; c++) |
|
43 |
for(int c=1; c<mNumCubitsInThisPhase; c++)
|
|
42 | 44 |
{ |
43 | 45 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
44 | 46 |
x = tmp[0]; |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicPerm1.java | ||
---|---|---|
24 | 24 |
|
25 | 25 |
public PhaseCyclicPerm1(SolvedObject object, int cubit, int quat) |
26 | 26 |
{ |
27 |
super(object); |
|
28 |
|
|
27 | 29 |
Static4D[] objectQuats = object.getQuats(); |
28 | 30 |
Static4D q = objectQuats[quat]; |
29 | 31 |
double alpha = 2*Math.acos(q.get3()); |
30 | 32 |
double numTurns = 2*Math.PI / alpha; |
31 |
mNumCubits = (int)(numTurns+0.5f); |
|
33 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f);
|
|
32 | 34 |
|
33 |
mCubitGroups = new int[1][mNumCubits]; |
|
35 |
mCubitGroups = new int[1][mNumCubitsInThisPhase];
|
|
34 | 36 |
mNumGroups = 1; |
35 | 37 |
mObjectQuats = objectQuats; |
36 | 38 |
|
... | ... | |
45 | 47 |
|
46 | 48 |
mCubitGroups[0][0] = cubit; |
47 | 49 |
|
48 |
for(int c=1; c<mNumCubits; c++) |
|
50 |
for(int c=1; c<mNumCubitsInThisPhase; c++)
|
|
49 | 51 |
{ |
50 | 52 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
51 | 53 |
x = tmp[0]; |
... | ... | |
86 | 88 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
87 | 89 |
|
88 | 90 |
@Override |
89 |
public int[] endQuatIndices(SolvedObject object, int cubitQuat, int cubit)
|
|
91 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
90 | 92 |
{ |
91 | 93 |
float[] thisPos = mPositions[cubit]; |
92 | 94 |
int numQuats = mObjectQuats.length; |
... | ... | |
100 | 102 |
|
101 | 103 |
for(int q=0; q<numQuats; q++) |
102 | 104 |
{ |
103 |
int qn = object.getMultQuat(q,cubitQuat); // i.e. if we first rotate cubit by cubitQuat then it ends |
|
104 |
// up in (x,y,z) (current position) and then by q and it |
|
105 |
// ends up in final pos (but not necessarily final orientation) |
|
106 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,mObjectQuats[qn]); |
|
105 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,mObjectQuats[q]); |
|
107 | 106 |
|
108 | 107 |
float dx = tmp[0] - x; |
109 | 108 |
float dy = tmp[1] - y; |
... | ... | |
113 | 112 |
if( err < MAX_ERROR ) |
114 | 113 |
{ |
115 | 114 |
numGoodQuats++; |
116 |
tmpQuats[qn] = 1;
|
|
115 |
tmpQuats[q] = 1; |
|
117 | 116 |
} |
118 | 117 |
} |
119 | 118 |
|
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicPerm2.java | ||
---|---|---|
19 | 19 |
{ |
20 | 20 |
public PhaseCyclicPerm2(SolvedObject object, int cubit, int quat) |
21 | 21 |
{ |
22 |
super(object); |
|
23 |
|
|
22 | 24 |
Static4D[] objectQuats = object.getQuats(); |
23 | 25 |
Static4D q = objectQuats[quat]; |
24 | 26 |
double alpha = 2*Math.acos(q.get3()); |
25 | 27 |
double numTurns = 2*Math.PI / alpha; |
26 |
mNumCubits = (int)(numTurns+0.5f); |
|
28 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f);
|
|
27 | 29 |
|
28 |
mCubitGroups = new int[1][mNumCubits]; |
|
30 |
mCubitGroups = new int[1][mNumCubitsInThisPhase];
|
|
29 | 31 |
mNumGroups = 1; |
30 | 32 |
|
31 | 33 |
float[][] positions = object.getCubitPositions(); |
... | ... | |
38 | 40 |
|
39 | 41 |
mCubitGroups[0][0] = cubit; |
40 | 42 |
|
41 |
for(int c=1; c<mNumCubits; c++) |
|
43 |
for(int c=1; c<mNumCubitsInThisPhase; c++)
|
|
42 | 44 |
{ |
43 | 45 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
44 | 46 |
x = tmp[0]; |
src/main/java/org/distorted/objectlib/algphases/PhaseMitm.java | ||
---|---|---|
11 | 11 |
|
12 | 12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
13 | 13 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
14 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
14 | 15 |
|
15 | 16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
16 | 17 |
|
... | ... | |
20 | 21 |
private final static double MAX_SEARCH = 10000000.0; // max 10mln positions back-searched |
21 | 22 |
|
22 | 23 |
private boolean[] mSolved; |
23 |
private int[][] mTmp; |
|
24 | 24 |
private int[] mWhichSubphase; |
25 | 25 |
private int mForwardDepth, mBackwardDepth; |
26 |
private int mDepth; |
|
26 |
private int mDepth, mGroup; |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
PhaseMitm(SolvedObject object) |
|
31 |
{ |
|
32 |
super(object); |
|
33 |
} |
|
27 | 34 |
|
28 | 35 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
29 | 36 |
// Only attempt to find solutions which are not longer than maxlen; if not found, return null. |
... | ... | |
43 | 50 |
int tmpBackward= depth-tmpForward; |
44 | 51 |
|
45 | 52 |
table.build(object,tmpForward); |
46 |
return table.tryReaching(object,mEndQuats,tmpBackward,tmpForward);
|
|
53 |
return table.tryReaching(object,mTargetQuats,tmpBackward,tmpForward);
|
|
47 | 54 |
} |
48 | 55 |
|
49 | 56 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
50 | 57 |
|
51 | 58 |
private int prepareForSubPhase(SolvedObject object, MitmTable table) |
52 | 59 |
{ |
53 |
table.prepareForSubPhase(mEndQuats);
|
|
60 |
table.prepareForSubPhase(mTargetQuats);
|
|
54 | 61 |
int bytesPerEntry = table.getBytesPerEntry(); |
55 | 62 |
int branchingFactor = object.getBranchingFactor(); |
56 | 63 |
|
... | ... | |
75 | 82 |
|
76 | 83 |
private int computeBackwardDepth(int branchingFactor) |
77 | 84 |
{ |
78 |
int multiplier = 1; |
|
79 |
|
|
80 |
for( int[] quats : mEndQuats ) |
|
81 |
if( quats!=null ) multiplier *= quats.length; |
|
82 |
|
|
85 |
int multiplier = mTargetQuats.computeNumCombinations(); |
|
83 | 86 |
double maxDepth = Math.log(MAX_SEARCH/multiplier) / Math.log(branchingFactor); |
84 |
|
|
85 | 87 |
return (int)maxDepth; |
86 | 88 |
} |
87 | 89 |
|
... | ... | |
106 | 108 |
@Override |
107 | 109 |
public void prepareForSubphases() |
108 | 110 |
{ |
109 |
int numEndQuats = mEndQuats.length; |
|
110 | 111 |
mSolved = new boolean[mNumGroups]; |
111 |
mTmp = new int[numEndQuats][]; |
|
112 |
mWhichSubphase = new int[numEndQuats]; |
|
112 |
mWhichSubphase = new int[mNumCubits]; |
|
113 | 113 |
|
114 |
for(int c=0; c<numEndQuats; c++) mWhichSubphase[c] = whichSubPhase(c);
|
|
114 |
for(int c=0; c<mNumCubits; c++) mWhichSubphase[c] = whichSubPhase(c);
|
|
115 | 115 |
for(int s=0; s<mNumGroups; s++) mSolved[s] = false; |
116 | 116 |
mDepth = 0; |
117 |
mGroup = 0; |
|
117 | 118 |
} |
118 | 119 |
|
119 | 120 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
150 | 151 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
151 | 152 |
|
152 | 153 |
@Override |
153 |
public boolean solveAnySubphase( SolvedObject object, MitmTable table, int[][] solution, int solIndex)
|
|
154 |
public boolean solveAnySubphase( SolvedObject object, MitmTable table, int[][] solution, int subPhase)
|
|
154 | 155 |
{ |
155 |
int maxDepth = mDepth; |
|
156 |
int numQuats = mEndQuats.length; |
|
157 |
System.arraycopy(mEndQuats, 0, mTmp, 0, numQuats); |
|
156 |
int maxDepth = mDepth+1; // this might mean that we do one extra depth, but if we set it to |
|
157 |
// mDepth then if after current mGroups there are no more unsolved |
|
158 |
// subgroups, we will simply give up and end solving altogether! |
|
159 |
|
|
160 |
TargetQuats tmp = new TargetQuats(mTargetQuats); |
|
158 | 161 |
|
159 |
for( ; mDepth<=maxDepth; mDepth++) |
|
160 |
for(int p=0; p<mNumGroups; p++)
|
|
161 |
if( !mSolved[p] )
|
|
162 |
for( ; mDepth<=maxDepth; mDepth++,mGroup=0)
|
|
163 |
for(int g=mGroup; g<mNumGroups; g++)
|
|
164 |
if( !mSolved[g] )
|
|
162 | 165 |
{ |
163 |
for(int q=0; q<numQuats; q++)
|
|
166 |
for(int q=0; q<mNumCubits; q++)
|
|
164 | 167 |
{ |
165 |
// -1 means that the cubit belongs to the previous (or next) phase. Cubits belonging to the
|
|
166 |
// next phase already have their endQuats set to null (see PhasedSolver.figureOutEndQuatIndices)
|
|
167 |
// Here we set to null (i.e. - mark that we do not care about) the quats of all cubits which
|
|
168 |
// -1 means that the cubit doesn't belong to the current phase. Cubits belonging to
|
|
169 |
// the next phase already have their targetQuats set to null (see Phase.setTargetQuats)
|
|
170 |
// Here we set to null (mark that we do not care about) the quats of all cubits which |
|
168 | 171 |
// belong to the current phase and haven't been solved yet (except the current subphase!). |
169 |
int sp = mWhichSubphase[q]; |
|
170 |
mEndQuats[q] = (sp==-1 || sp==p || mSolved[sp]) ? mTmp[q] : null; |
|
172 |
int wsp = mWhichSubphase[q]; |
|
173 |
int[] newValue = (wsp==-1 || wsp==g || mSolved[wsp]) ? tmp.getQuat(q) : null; |
|
174 |
mTargetQuats.setQuat(newValue,q); |
|
171 | 175 |
} |
172 | 176 |
maxDepth = prepareForSubPhase(object,table); |
173 |
solution[solIndex] = findSol(object,table,mDepth);
|
|
177 |
solution[subPhase] = findSol(object,table,mDepth);
|
|
174 | 178 |
|
175 |
if( solution[solIndex]!=null )
|
|
179 |
if( solution[subPhase]!=null )
|
|
176 | 180 |
{ |
177 |
System.arraycopy(mTmp, 0, mEndQuats, 0, numQuats); |
|
178 |
mSolved[p] = true; |
|
181 |
mTargetQuats.set(tmp); |
|
182 |
mSolved[g] = true; |
|
183 |
mGroup = g+1; // when we get called next time, do not repeat the calculations |
|
179 | 184 |
return true; |
180 | 185 |
} |
181 | 186 |
} |
182 | 187 |
|
183 |
System.arraycopy(mTmp, 0, mEndQuats, 0, numQuats);
|
|
188 |
mTargetQuats.set(tmp);
|
|
184 | 189 |
return false; |
185 | 190 |
} |
186 | 191 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseNotCyclic.java | ||
---|---|---|
9 | 9 |
|
10 | 10 |
package org.distorted.objectlib.algphases; |
11 | 11 |
|
12 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
13 |
|
|
12 | 14 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
13 | 15 |
|
14 | 16 |
public class PhaseNotCyclic extends PhaseMitm |
15 | 17 |
{ |
16 |
public PhaseNotCyclic(int[][] cubitgroups) |
|
18 |
public PhaseNotCyclic(SolvedObject object, int[][] cubitgroups)
|
|
17 | 19 |
{ |
20 |
super(object); |
|
21 |
|
|
18 | 22 |
mCubitGroups = cubitgroups; |
19 | 23 |
mNumGroups = cubitgroups.length; |
20 | 24 |
|
21 | 25 |
int numCubits = 0; |
22 | 26 |
for(int g=0; g<mNumGroups; g++) numCubits += mCubitGroups[g].length; |
23 | 27 |
|
24 |
mNumCubits = numCubits; |
|
28 |
mNumCubitsInThisPhase = numCubits;
|
|
25 | 29 |
} |
26 | 30 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseRegex.java | ||
---|---|---|
12 | 12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
13 | 13 |
import org.distorted.objectlib.algsolvers.MoveRegex; |
14 | 14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
15 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
15 | 16 |
|
16 | 17 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
17 | 18 |
|
... | ... | |
29 | 30 |
|
30 | 31 |
public PhaseRegex(SolvedObject object, String regex, int[][] cubitgroups) |
31 | 32 |
{ |
33 |
super(object); |
|
34 |
|
|
32 | 35 |
mCubitGroups = cubitgroups; |
33 | 36 |
mNumGroups = cubitgroups.length; |
34 | 37 |
mRegex = new MoveRegex(object,regex); |
... | ... | |
38 | 41 |
int numCubits = 0; |
39 | 42 |
for(int g=0; g<mNumGroups; g++) numCubits += mCubitGroups[g].length; |
40 | 43 |
|
41 |
mNumCubits = numCubits; |
|
44 |
mNumCubitsInThisPhase = numCubits;
|
|
42 | 45 |
|
43 | 46 |
mSolved = new boolean[mNumGroups]; |
44 | 47 |
} |
45 | 48 |
|
46 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
47 |
|
|
48 |
private boolean quatsMatchEndQuats(int[] quats) |
|
49 |
{ |
|
50 |
int numQuats = quats.length; |
|
51 |
|
|
52 |
for(int q=0; q<numQuats; q++) |
|
53 |
{ |
|
54 |
int[] eq = mEndQuats[q]; |
|
55 |
if( eq!=null && doesntMatch(quats[q],eq) ) return false; |
|
56 |
} |
|
57 |
|
|
58 |
return true; |
|
59 |
} |
|
60 |
|
|
61 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
62 |
|
|
63 |
private boolean doesntMatch(int quat, int[] endquats) |
|
64 |
{ |
|
65 |
for(int endquat : endquats) |
|
66 |
if( quat==endquat ) return false; |
|
67 |
|
|
68 |
return true; |
|
69 |
} |
|
70 |
|
|
71 | 49 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
72 | 50 |
|
73 | 51 |
private int findMove(int ax, int row, int angle) |
... | ... | |
165 | 143 |
|
166 | 144 |
public void prepareForSubphases() |
167 | 145 |
{ |
168 |
int numEndQuats = mEndQuats.length; |
|
169 |
mTmp = new int[numEndQuats][]; |
|
170 |
mWhichSubphase = new int[numEndQuats]; |
|
146 |
mTmp = new int[mNumCubits][]; |
|
147 |
mWhichSubphase = new int[mNumCubits]; |
|
171 | 148 |
|
172 |
for(int c=0; c<numEndQuats; c++) mWhichSubphase[c] = whichSubPhase(c);
|
|
149 |
for(int c=0; c<mNumCubits; c++) mWhichSubphase[c] = whichSubPhase(c);
|
|
173 | 150 |
for(int s=0; s<mNumGroups; s++) mSolved[s] = false; |
174 | 151 |
} |
175 | 152 |
|
... | ... | |
186 | 163 |
int numMoves = (moveSeq==null ? 0 : moveSeq.length); |
187 | 164 |
for(int m=1; m<numMoves; m++) object.makeMove(moveSeq[m]); |
188 | 165 |
int[] qts = object.getCubitQuats(); |
189 |
boolean solved = quatsMatchEndQuats(qts);
|
|
166 |
boolean solved = mTargetQuats.matchesQuats(qts);
|
|
190 | 167 |
object.setUpStartingQuats(quats); |
191 | 168 |
if( solved ) return simplify(moveSeq); |
192 | 169 |
moveSeq = mRegex.getNext(); |
... | ... | |
200 | 177 |
|
201 | 178 |
public boolean solveAnySubphase(SolvedObject object, MitmTable table, int[][] solution, int solIndex) |
202 | 179 |
{ |
203 |
int numQuats = mEndQuats.length; |
|
204 |
System.arraycopy(mEndQuats, 0, mTmp, 0, numQuats); |
|
180 |
TargetQuats tmp = new TargetQuats(mTargetQuats); |
|
205 | 181 |
|
206 | 182 |
for(int p=0; p<mNumGroups; p++) |
207 | 183 |
if( !mSolved[p] ) |
208 | 184 |
{ |
209 |
for(int q=0; q<numQuats; q++)
|
|
185 |
for(int q=0; q<mNumCubits; q++)
|
|
210 | 186 |
{ |
211 | 187 |
// -1 means that the cubit belongs to the previous (or next) phase. Cubits belonging to the |
212 | 188 |
// next phase already have their endQuats set to null (see PhasedSolver.figureOutEndQuatIndices) |
213 | 189 |
// Here we set to null (i.e. - mark that we do not care about) the quats of all cubits which |
214 | 190 |
// belong to the current phase and haven't been solved yet (except the current subphase!). |
215 | 191 |
int sp = mWhichSubphase[q]; |
216 |
mEndQuats[q] = (sp==-1 || sp==p || mSolved[sp]) ? mTmp[q] : null; |
|
192 |
int[] newValue = (sp==-1 || sp==p || mSolved[sp]) ? mTmp[q] : null; |
|
193 |
mTargetQuats.setQuat(newValue,q); |
|
217 | 194 |
} |
218 | 195 |
|
219 | 196 |
solution[solIndex] = findSolution(object,table); |
220 | 197 |
|
221 | 198 |
if( solution[solIndex]!=null ) |
222 | 199 |
{ |
223 |
System.arraycopy(mTmp, 0, mEndQuats, 0, numQuats);
|
|
200 |
mTargetQuats.set(tmp);
|
|
224 | 201 |
mSolved[p] = true; |
225 | 202 |
return true; |
226 | 203 |
} |
227 | 204 |
} |
228 | 205 |
|
229 |
System.arraycopy(mTmp, 0, mEndQuats, 0, numQuats);
|
|
206 |
mTargetQuats.set(tmp);
|
|
230 | 207 |
return false; |
231 | 208 |
} |
232 | 209 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MitmTable.java | ||
---|---|---|
124 | 124 |
|
125 | 125 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
126 | 126 |
|
127 |
public void prepareForSubPhase(int[][] endQuats)
|
|
127 |
public void prepareForSubPhase(TargetQuats quats)
|
|
128 | 128 |
{ |
129 |
int numUsedCubits = 0; |
|
130 |
|
|
131 |
for(int e=0; e<mNumCubits; e++) |
|
132 |
{ |
|
133 |
if( endQuats[e]!=null ) |
|
134 |
{ |
|
135 |
numUsedCubits++; |
|
136 |
mUseCubit[e] = true; |
|
137 |
} |
|
138 |
else |
|
139 |
{ |
|
140 |
mUseCubit[e] = false; |
|
141 |
} |
|
142 |
} |
|
143 |
|
|
129 |
int numUsedCubits = quats.computeUsedCubitTable(mUseCubit); |
|
144 | 130 |
double numBytes = numUsedCubits*mBitsPerQuat/8.0; |
145 | 131 |
mBytesPerEntry = (int)Math.ceil(numBytes); // this many bytes will be needed to store one position |
146 | 132 |
mBuildDepth = -1; |
... | ... | |
169 | 155 |
// {0} means solution found and it's empty (position already solved) |
170 | 156 |
// {2,1,3} means the solution is 2 moves long, and the indices of moves to make are 1 and 3. |
171 | 157 |
|
172 |
public int[] tryReaching(SolvedObject object, int[][] endQuats, int lenb, int lenf)
|
|
158 |
public int[] tryReaching(SolvedObject object, TargetQuats target, int lenb, int lenf)
|
|
173 | 159 |
{ |
174 |
int[] indices = new int[mNumCubits]; |
|
175 |
boolean thereIsNext; |
|
176 | 160 |
int branching = object.getBranchingFactor(); |
177 | 161 |
int[] backward = new int[lenb]; |
178 | 162 |
int[] rem = object.getCopiedCubitQuats(); |
163 |
int[] quats = target.getFirst(); |
|
179 | 164 |
|
180 | 165 |
do |
181 | 166 |
{ |
182 |
object.setUpStartingQuats(endQuats,indices);
|
|
167 |
object.setUpStartingQuats(quats);
|
|
183 | 168 |
byte[] reached = tryReachingRecursive(object,branching,lenb,backward); |
184 | 169 |
|
185 | 170 |
if( reached!=null ) |
... | ... | |
190 | 175 |
return joinSequences(forward,numMoves,backward); |
191 | 176 |
} |
192 | 177 |
|
193 |
thereIsNext = getNext(endQuats,indices);
|
|
178 |
quats = target.getNext();
|
|
194 | 179 |
} |
195 |
while( thereIsNext );
|
|
180 |
while( quats!=null );
|
|
196 | 181 |
|
197 | 182 |
object.setUpStartingQuats(rem); |
198 | 183 |
return null; |
... | ... | |
337 | 322 |
} |
338 | 323 |
} |
339 | 324 |
|
340 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
341 |
|
|
342 |
private boolean getNext(int[][] quats, int[] indices) |
|
343 |
{ |
|
344 |
for(int i=indices.length-1; i>=0; i--) |
|
345 |
{ |
|
346 |
int[] q = quats[i]; |
|
347 |
int len = q!=null ? q.length-1 : 0; |
|
348 |
|
|
349 |
if( indices[i]<len ) |
|
350 |
{ |
|
351 |
indices[i]++; |
|
352 |
return true; |
|
353 |
} |
|
354 |
} |
|
355 |
|
|
356 |
return false; |
|
357 |
} |
|
358 |
|
|
359 | 325 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
360 | 326 |
// Find index'th entry in the table 'output'; it contains 8 bits. Write 'value' to it, but only |
361 | 327 |
// its 'toBeWritten' first bits (out of the 'remaining' bits), and at offset 'offset' in the table. |
src/main/java/org/distorted/objectlib/algsolvers/PhasedSolver.java | ||
---|---|---|
16 | 16 |
|
17 | 17 |
public class PhasedSolver |
18 | 18 |
{ |
19 |
private static final int[] INDICES = {0}; |
|
20 |
|
|
21 | 19 |
private final Phase[] mPhases; |
22 | 20 |
private final SolvedObject mObject; |
23 | 21 |
private final MitmTable mTable; |
... | ... | |
58 | 56 |
|
59 | 57 |
int[] findSolutionSubphases(Phase phase, int numSubphases) |
60 | 58 |
{ |
61 |
int solIndex=0; |
|
62 |
int[][] endQuats = phase.getEndQuats(); |
|
63 |
int numEndQuats = endQuats.length; |
|
64 |
int[][] solution = new int[numEndQuats][]; |
|
59 |
int subPhase=0; |
|
60 |
int[][] solution = new int[numSubphases][]; |
|
65 | 61 |
|
66 | 62 |
phase.prepareForSubphases(); |
67 | 63 |
|
68 |
for(; solIndex<numSubphases; solIndex++)
|
|
69 |
if( !phase.solveAnySubphase(mObject,mTable,solution,solIndex) )
|
|
64 |
for(; subPhase<numSubphases; subPhase++)
|
|
65 |
if( !phase.solveAnySubphase(mObject,mTable,solution,subPhase) )
|
|
70 | 66 |
{ |
71 |
System.out.println("findSolutionSubphases: failed to solve subphase "+solIndex);
|
|
67 |
System.out.println("findSolutionSubphases: failed to solve subphase "+subPhase);
|
|
72 | 68 |
break; |
73 | 69 |
} |
74 | 70 |
|
75 |
if( solIndex>0 )
|
|
71 |
if( subPhase>0 )
|
|
76 | 72 |
{ |
77 | 73 |
int index=1, num=1; |
78 |
for(int i=0; i<solIndex; i++) num += (solution[i].length-1);
|
|
74 |
for(int i=0; i<subPhase; i++) num += (solution[i].length-1);
|
|
79 | 75 |
|
80 | 76 |
int[] ret = new int[num]; |
81 | 77 |
ret[0] = num-1; |
82 | 78 |
|
83 |
for(int i=0; i<solIndex; i++)
|
|
79 |
for(int i=0; i<subPhase; i++)
|
|
84 | 80 |
{ |
85 | 81 |
int len = solution[i].length; |
86 | 82 |
for(int j=1; j<len; j++) ret[index++] = solution[i][j]; |
... | ... | |
94 | 90 |
|
95 | 91 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
96 | 92 |
|
97 |
private int[] figureOutEndQuatIndices(int cubitQuat, int phase, int cubit)
|
|
93 |
private int[] solutionOfPhase(int currentPhase)
|
|
98 | 94 |
{ |
99 |
for(int p=0; p<phase; p++) |
|
100 |
if( mPhases[p].contains(cubit) ) return INDICES; |
|
101 |
|
|
102 |
if( mPhases[phase].contains(cubit) ) |
|
103 |
return mPhases[phase].endQuatIndices(mObject,cubitQuat,cubit); |
|
104 |
|
|
105 |
return null; |
|
106 |
} |
|
107 |
|
|
108 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
109 |
// quats get overwritten at the end of the phase |
|
110 |
// return null on error |
|
111 |
|
|
112 |
private int[] solutionOfPhase(int phase, int[] quats) |
|
113 |
{ |
|
114 |
Phase p = mPhases[phase]; |
|
115 |
int numSubphases = p.numSubphases(); |
|
116 | 95 |
int numCubits = mPositions.length; |
117 |
int[][] endQuats = new int[numCubits][];
|
|
96 |
boolean[] previousPhases = new boolean[numCubits];
|
|
118 | 97 |
|
119 | 98 |
for(int c=0; c<numCubits; c++) |
120 |
{ |
|
121 |
endQuats[c] = figureOutEndQuatIndices(quats[c],phase,c); |
|
122 |
} |
|
99 |
for(int p=0; p<currentPhase; p++) |
|
100 |
if( mPhases[p].contains(c) ) |
|
101 |
{ |
|
102 |
previousPhases[c] = true; |
|
103 |
break; |
|
104 |
} |
|
123 | 105 |
|
124 |
p.setEndQuats(endQuats); |
|
106 |
Phase phase = mPhases[currentPhase]; |
|
107 |
int numSubphases = phase.numSubphases(); |
|
108 |
phase.setTargetQuats(mObject,previousPhases); |
|
125 | 109 |
|
126 | 110 |
if( numSubphases>1 ) |
127 | 111 |
{ |
128 |
return findSolutionSubphases(p,numSubphases); |
|
112 |
return findSolutionSubphases(phase,numSubphases);
|
|
129 | 113 |
} |
130 | 114 |
else |
131 | 115 |
{ |
132 |
return p.findSolution(mObject,mTable); |
|
116 |
return phase.findSolution(mObject,mTable);
|
|
133 | 117 |
} |
134 | 118 |
} |
135 | 119 |
|
... | ... | |
143 | 127 |
int[][] solution_moves = new int[mNumPhases][]; |
144 | 128 |
prepareForSolution(quats); |
145 | 129 |
|
146 |
for(int i=0; i<mNumPhases; i++)
|
|
130 |
for(int p=0; p<mNumPhases; p++)
|
|
147 | 131 |
{ |
148 |
solution_moves[i] = solutionOfPhase(i,quats);
|
|
132 |
solution_moves[p] = solutionOfPhase(p);
|
|
149 | 133 |
|
150 |
if( solution_moves[i]==null )
|
|
134 |
if( solution_moves[p]==null )
|
|
151 | 135 |
{ |
152 |
System.out.println("AlgSolver: error solving phase "+i);
|
|
136 |
System.out.println("AlgSolver: error solving phase "+p);
|
|
153 | 137 |
break; |
154 | 138 |
} |
155 | 139 |
else |
156 | 140 |
{ |
157 | 141 |
long next = System.currentTimeMillis(); |
158 |
System.out.println("AlgSolver: phase "+i+" solution len: "+solution_moves[i][0]+" time: "+(next-millis));
|
|
142 |
System.out.println("AlgSolver: phase "+p+" solution len: "+solution_moves[p][0]+" time: "+(next-millis));
|
|
159 | 143 |
millis = next; |
160 | 144 |
} |
161 | 145 |
} |
src/main/java/org/distorted/objectlib/algsolvers/SolvedObject.java | ||
---|---|---|
69 | 69 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
70 | 70 |
|
71 | 71 |
public void setUpStartingQuats(int[] quats) { mCubits.setUpQuats(quats); } |
72 |
public void setUpStartingQuats(int[][] quats, int[] indices) { mCubits.setUpQuats(quats,indices); } |
|
73 | 72 |
public void makeMove(int moveIndex) { mCubits.makeMove(moveIndex); } |
74 | 73 |
public void backMove(int moveIndex) { mCubits.backMove(moveIndex); } |
75 | 74 |
public int[] getCubitQuats() { return mCubits.getRotQuats(); } |
src/main/java/org/distorted/objectlib/algsolvers/SolvedObjectCubit.java | ||
---|---|---|
119 | 119 |
for(int c=0; c<mNumCubits; c++) mRotQuats[c] = quats[c]; |
120 | 120 |
} |
121 | 121 |
|
122 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
123 |
// here we set the indices of cubits we don't care about at the moment to -1. |
|
124 |
|
|
125 |
void setUpQuats(int[][] quats, int[] indices) |
|
126 |
{ |
|
127 |
for(int c=0; c<mNumCubits; c++) |
|
128 |
{ |
|
129 |
int[] q = quats[c]; |
|
130 |
mRotQuats[c] = q!=null ? q[indices[c]] : -1; |
|
131 |
} |
|
132 |
} |
|
133 |
|
|
134 | 122 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
135 | 123 |
|
136 | 124 |
int[] getRotQuats() |
src/main/java/org/distorted/objectlib/algsolvers/TargetQuats.java | ||
---|---|---|
1 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
2 |
// Copyright 2024 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.algsolvers; |
|
11 |
|
|
12 |
public class TargetQuats |
|
13 |
{ |
|
14 |
private final int[][] mEndQuats; |
|
15 |
private final int[] mTmp; |
|
16 |
private final int[] mIndices; |
|
17 |
|
|
18 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
19 |
|
|
20 |
public TargetQuats(int[][] endQuats) |
|
21 |
{ |
|
22 |
int len = endQuats.length; |
|
23 |
mEndQuats = endQuats; |
|
24 |
mTmp = new int[len]; |
|
25 |
mIndices = new int[len]; |
|
26 |
} |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
public TargetQuats(TargetQuats source) |
|
31 |
{ |
|
32 |
int len = source.mEndQuats.length; |
|
33 |
mEndQuats = new int[len][]; |
|
34 |
System.arraycopy(source.mEndQuats,0,mEndQuats,0,len); |
|
35 |
mTmp = new int[len]; |
|
36 |
mIndices = new int[len]; |
|
37 |
} |
|
38 |
|
|
39 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
40 |
|
|
41 |
public String debug() |
|
42 |
{ |
|
43 |
return MitmTable.getMultiQuatString(mEndQuats); |
|
44 |
} |
|
45 |
|
|
46 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
47 |
|
|
48 |
public void set(TargetQuats source) |
|
49 |
{ |
|
50 |
int len = mEndQuats.length; |
|
51 |
System.arraycopy(source.mEndQuats,0,mEndQuats,0,len); |
|
52 |
} |
|
53 |
|
|
54 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
55 |
|
|
56 |
public void setQuat(int[] source, int quat) |
|
57 |
{ |
|
58 |
mEndQuats[quat] = source; |
|
59 |
} |
|
60 |
|
|
61 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
62 |
|
|
63 |
public int[] getQuat(int quat) |
|
64 |
{ |
|
65 |
return mEndQuats[quat]; |
|
66 |
} |
|
67 |
|
|
68 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
69 |
// how many combinations are we going to have to start from when reachingBack to the MitmTable? |
|
70 |
|
|
71 |
public int computeNumCombinations() |
|
72 |
{ |
|
73 |
int num = 1; |
|
74 |
|
|
75 |
for( int[] quats : mEndQuats ) |
|
76 |
if( quats!=null ) num *= quats.length; |
|
77 |
|
|
78 |
return num; |
|
79 |
} |
|
80 |
|
|
81 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
82 |
|
|
83 |
public int computeUsedCubitTable(boolean[] table) |
|
84 |
{ |
|
85 |
int len = mEndQuats.length; |
|
86 |
int numUsedCubits = 0; |
|
87 |
|
|
88 |
for(int e=0; e<len; e++) |
|
89 |
{ |
|
90 |
if( mEndQuats[e]!=null ) |
|
91 |
{ |
|
92 |
numUsedCubits++; |
|
93 |
table[e] = true; |
|
94 |
} |
|
95 |
else |
|
96 |
{ |
|
97 |
table[e] = false; |
|
98 |
} |
|
99 |
} |
|
100 |
|
|
101 |
return numUsedCubits; |
|
102 |
} |
|
103 |
|
|
104 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
105 |
|
|
106 |
public int[] getFirst() |
|
107 |
{ |
|
108 |
int len = mEndQuats.length; |
|
109 |
for(int q=0; q<len; q++) mIndices[q] = 0; |
|
110 |
return getCurrent(); |
|
111 |
} |
|
112 |
|
|
113 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
114 |
|
|
115 |
public int[] getNext() |
|
116 |
{ |
|
117 |
if( incIndices() ) return getCurrent(); |
|
118 |
return null; |
|
119 |
} |
|
120 |
|
|
121 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
122 |
|
|
123 |
public boolean matchesQuats(int[] quats) |
|
124 |
{ |
|
125 |
int numQuats = quats.length; |
|
126 |
|
|
127 |
for(int q=0; q<numQuats; q++) |
|
128 |
{ |
|
129 |
int[] eq = mEndQuats[q]; |
|
130 |
if( eq!=null && doesntMatch(quats[q],eq) ) return false; |
|
131 |
} |
|
132 |
|
|
133 |
return true; |
|
134 |
} |
|
135 |
|
|
136 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
137 |
|
|
138 |
private boolean incIndices() |
|
139 |
{ |
|
140 |
for(int i=mIndices.length-1; i>=0; i--) |
|
141 |
{ |
|
142 |
int[] q = mEndQuats[i]; |
|
143 |
int len = q!=null ? q.length-1 : 0; |
|
144 |
|
|
145 |
if( mIndices[i]<len ) |
|
146 |
{ |
|
147 |
mIndices[i]++; |
|
148 |
return true; |
|
149 |
} |
|
150 |
} |
|
151 |
|
|
152 |
return false; |
|
153 |
} |
|
154 |
|
|
155 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
156 |
|
|
157 |
private boolean doesntMatch(int quat, int[] endquats) |
|
158 |
{ |
|
159 |
for(int endquat : endquats) |
|
160 |
if( quat==endquat ) return false; |
|
161 |
|
|
162 |
return true; |
|
163 |
} |
|
164 |
|
|
165 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
166 |
|
|
167 |
private int[] getCurrent() |
|
168 |
{ |
|
169 |
int len = mEndQuats.length; |
|
170 |
|
|
171 |
for(int q=0; q<len; q++) |
|
172 |
{ |
|
173 |
int[] qs = mEndQuats[q]; |
|
174 |
mTmp[q] = (qs==null ? -1 : qs[mIndices[q]]); |
|
175 |
} |
|
176 |
|
|
177 |
return mTmp; |
|
178 |
} |
|
179 |
} |
Also available in: Unified diff
Progress with PhasedSolver.
Introduce an abstracted TargetQuats.