Revision 149ee2dc
Added by Leszek Koltunski 9 months ago
src/main/java/org/distorted/objectlib/algphases/Phase.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
|
13 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
14 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
abstract public class Phase |
|
19 |
{ |
|
20 |
private static final int[] INDICES = {0}; |
|
21 |
|
|
22 |
protected int[][] mCubitGroups; |
|
23 |
protected int mNumGroups; |
|
24 |
protected int mNumCubitsInThisPhase; |
|
25 |
protected int mNumCubits; |
|
26 |
protected TargetQuats mTargetQuats; |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
Phase(SolvedObject object) |
|
31 |
{ |
|
32 |
float[][] pos = object.getCubitPositions(); |
|
33 |
mNumCubits = pos.length; |
|
34 |
} |
|
35 |
|
|
36 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
37 |
|
|
38 |
abstract public void prepareForSubphases(); |
|
39 |
abstract public int[] findSolution(SolvedObject object, MitmTable table); |
|
40 |
abstract public boolean solveAnySubphase(SolvedObject object, MitmTable table, int[][] solution, int solIndex); |
|
41 |
|
|
42 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
43 |
|
|
44 |
public int numSubphases() |
|
45 |
{ |
|
46 |
return mNumGroups; |
|
47 |
} |
|
48 |
|
|
49 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
|
51 |
public int whichSubPhase(int cubit) |
|
52 |
{ |
|
53 |
for(int g=0; g<mNumGroups; g++) |
|
54 |
for(int j : mCubitGroups[g]) |
|
55 |
if( cubit==j ) return g; |
|
56 |
|
|
57 |
return -1; |
|
58 |
} |
|
59 |
|
|
60 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
61 |
|
|
62 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
63 |
{ |
|
64 |
return INDICES; |
|
65 |
} |
|
66 |
|
|
67 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
68 |
|
|
69 |
public void setTargetQuats(SolvedObject object, boolean[] inPreviousPhases) |
|
70 |
{ |
|
71 |
int len = inPreviousPhases.length; |
|
72 |
|
|
73 |
int[][] target = new int[len][]; |
|
74 |
|
|
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); |
|
83 |
} |
|
84 |
|
|
85 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
86 |
|
|
87 |
public boolean contains(int cubit) |
|
88 |
{ |
|
89 |
for(int g=0; g<mNumGroups; g++) |
|
90 |
for(int c : mCubitGroups[g]) |
|
91 |
if( cubit==c ) return true; |
|
92 |
|
|
93 |
return false; |
|
94 |
} |
|
95 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicOrie1.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.library.helpers.QuatHelper; |
|
13 |
import org.distorted.library.type.Static4D; |
|
14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
public class PhaseCyclicOrie1 extends PhaseMitm |
|
19 |
{ |
|
20 |
private final int mCyclicQuat; |
|
21 |
|
|
22 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
23 |
|
|
24 |
public PhaseCyclicOrie1(SolvedObject object, int cubit, int quat) |
|
25 |
{ |
|
26 |
super(object); |
|
27 |
|
|
28 |
Static4D[] objectQuats = object.getQuats(); |
|
29 |
Static4D q = objectQuats[quat]; |
|
30 |
double alpha = 2*Math.acos(q.get3()); |
|
31 |
double numTurns = 2*Math.PI / alpha; |
|
32 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f); |
|
33 |
|
|
34 |
mCubitGroups = new int[1][mNumCubitsInThisPhase]; |
|
35 |
mNumGroups = 1; |
|
36 |
mCyclicQuat = quat; |
|
37 |
|
|
38 |
float[][] positions = object.getCubitPositions(); |
|
39 |
float[] pos = positions[cubit]; |
|
40 |
float x = pos[0]; |
|
41 |
float y = pos[1]; |
|
42 |
float z = pos[2]; |
|
43 |
|
|
44 |
float[] tmp = new float[4]; |
|
45 |
|
|
46 |
mCubitGroups[0][0] = cubit; |
|
47 |
|
|
48 |
for(int c=1; c<mNumCubitsInThisPhase; c++) |
|
49 |
{ |
|
50 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
|
51 |
x = tmp[0]; |
|
52 |
y = tmp[1]; |
|
53 |
z = tmp[2]; |
|
54 |
|
|
55 |
mCubitGroups[0][c] = whichPosIsThis(positions,tmp); |
|
56 |
} |
|
57 |
} |
|
58 |
|
|
59 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
60 |
|
|
61 |
private int whichPosIsThis(float[][] positions, float[] pos) |
|
62 |
{ |
|
63 |
int numPos = positions.length; |
|
64 |
float minErr = Float.MAX_VALUE; |
|
65 |
int ret=-1; |
|
66 |
|
|
67 |
for(int i=0; i<numPos; i++) |
|
68 |
{ |
|
69 |
float[] curr = positions[i]; |
|
70 |
float dx = curr[0] - pos[0]; |
|
71 |
float dy = curr[1] - pos[1]; |
|
72 |
float dz = curr[2] - pos[2]; |
|
73 |
|
|
74 |
float err = dx*dx + dy*dy + dz*dz; |
|
75 |
|
|
76 |
if( err < minErr ) |
|
77 |
{ |
|
78 |
minErr = err; |
|
79 |
ret = i; |
|
80 |
} |
|
81 |
} |
|
82 |
|
|
83 |
return ret; |
|
84 |
} |
|
85 |
|
|
86 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
87 |
|
|
88 |
@Override |
|
89 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
90 |
{ |
|
91 |
int[] retQuats = new int[mNumCubitsInThisPhase]; |
|
92 |
retQuats[0] = 0; |
|
93 |
retQuats[1] = mCyclicQuat; |
|
94 |
|
|
95 |
for(int i=2; i<mNumCubitsInThisPhase; i++) |
|
96 |
{ |
|
97 |
retQuats[i] = object.getMultQuat(mCyclicQuat,retQuats[i-1]); |
|
98 |
} |
|
99 |
|
|
100 |
return retQuats; |
|
101 |
} |
|
102 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicOrie2.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.library.helpers.QuatHelper; |
|
13 |
import org.distorted.library.type.Static4D; |
|
14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
public class PhaseCyclicOrie2 extends PhaseMitm |
|
19 |
{ |
|
20 |
public PhaseCyclicOrie2(SolvedObject object, int cubit, int quat) |
|
21 |
{ |
|
22 |
super(object); |
|
23 |
|
|
24 |
Static4D[] objectQuats = object.getQuats(); |
|
25 |
Static4D q = objectQuats[quat]; |
|
26 |
double alpha = 2*Math.acos(q.get3()); |
|
27 |
double numTurns = 2*Math.PI / alpha; |
|
28 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f); |
|
29 |
|
|
30 |
mCubitGroups = new int[1][mNumCubitsInThisPhase]; |
|
31 |
mNumGroups = 1; |
|
32 |
|
|
33 |
float[][] positions = object.getCubitPositions(); |
|
34 |
float[] pos = positions[cubit]; |
|
35 |
float x = pos[0]; |
|
36 |
float y = pos[1]; |
|
37 |
float z = pos[2]; |
|
38 |
|
|
39 |
float[] tmp = new float[4]; |
|
40 |
|
|
41 |
mCubitGroups[0][0] = cubit; |
|
42 |
|
|
43 |
for(int c=1; c<mNumCubitsInThisPhase; c++) |
|
44 |
{ |
|
45 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
|
46 |
x = tmp[0]; |
|
47 |
y = tmp[1]; |
|
48 |
z = tmp[2]; |
|
49 |
|
|
50 |
mCubitGroups[0][c] = whichPosIsThis(positions,tmp); |
|
51 |
} |
|
52 |
} |
|
53 |
|
|
54 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
55 |
|
|
56 |
private int whichPosIsThis(float[][] positions, float[] pos) |
|
57 |
{ |
|
58 |
int numPos = positions.length; |
|
59 |
float minErr = Float.MAX_VALUE; |
|
60 |
int ret=-1; |
|
61 |
|
|
62 |
for(int i=0; i<numPos; i++) |
|
63 |
{ |
|
64 |
float[] curr = positions[i]; |
|
65 |
float dx = curr[0] - pos[0]; |
|
66 |
float dy = curr[1] - pos[1]; |
|
67 |
float dz = curr[2] - pos[2]; |
|
68 |
|
|
69 |
float err = dx*dx + dy*dy + dz*dz; |
|
70 |
|
|
71 |
if( err < minErr ) |
|
72 |
{ |
|
73 |
minErr = err; |
|
74 |
ret = i; |
|
75 |
} |
|
76 |
} |
|
77 |
|
|
78 |
return ret; |
|
79 |
} |
|
80 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicPerm1.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.library.helpers.QuatHelper; |
|
13 |
import org.distorted.library.type.Static4D; |
|
14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
public class PhaseCyclicPerm1 extends PhaseMitm |
|
19 |
{ |
|
20 |
private final Static4D[] mObjectQuats; |
|
21 |
private final float[][] mPositions; |
|
22 |
|
|
23 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
24 |
|
|
25 |
public PhaseCyclicPerm1(SolvedObject object, int cubit, int quat) |
|
26 |
{ |
|
27 |
super(object); |
|
28 |
|
|
29 |
Static4D[] objectQuats = object.getQuats(); |
|
30 |
Static4D q = objectQuats[quat]; |
|
31 |
double alpha = 2*Math.acos(q.get3()); |
|
32 |
double numTurns = 2*Math.PI / alpha; |
|
33 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f); |
|
34 |
|
|
35 |
mCubitGroups = new int[1][mNumCubitsInThisPhase]; |
|
36 |
mNumGroups = 1; |
|
37 |
mObjectQuats = objectQuats; |
|
38 |
|
|
39 |
float[][] positions = object.getCubitPositions(); |
|
40 |
mPositions = positions; |
|
41 |
float[] pos = positions[cubit]; |
|
42 |
float x = pos[0]; |
|
43 |
float y = pos[1]; |
|
44 |
float z = pos[2]; |
|
45 |
|
|
46 |
float[] tmp = new float[4]; |
|
47 |
|
|
48 |
mCubitGroups[0][0] = cubit; |
|
49 |
|
|
50 |
for(int c=1; c<mNumCubitsInThisPhase; c++) |
|
51 |
{ |
|
52 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
|
53 |
x = tmp[0]; |
|
54 |
y = tmp[1]; |
|
55 |
z = tmp[2]; |
|
56 |
|
|
57 |
mCubitGroups[0][c] = whichPosIsThis(positions,tmp); |
|
58 |
} |
|
59 |
} |
|
60 |
|
|
61 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
62 |
|
|
63 |
private int whichPosIsThis(float[][] positions, float[] pos) |
|
64 |
{ |
|
65 |
int numPos = positions.length; |
|
66 |
float minErr = Float.MAX_VALUE; |
|
67 |
int ret=-1; |
|
68 |
|
|
69 |
for(int i=0; i<numPos; i++) |
|
70 |
{ |
|
71 |
float[] curr = positions[i]; |
|
72 |
float dx = curr[0] - pos[0]; |
|
73 |
float dy = curr[1] - pos[1]; |
|
74 |
float dz = curr[2] - pos[2]; |
|
75 |
|
|
76 |
float err = dx*dx + dy*dy + dz*dz; |
|
77 |
|
|
78 |
if( err < minErr ) |
|
79 |
{ |
|
80 |
minErr = err; |
|
81 |
ret = i; |
|
82 |
} |
|
83 |
} |
|
84 |
|
|
85 |
return ret; |
|
86 |
} |
|
87 |
|
|
88 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
89 |
|
|
90 |
@Override |
|
91 |
public int[] endQuatIndices(SolvedObject object, int cubit) |
|
92 |
{ |
|
93 |
float[] thisPos = mPositions[cubit]; |
|
94 |
int numQuats = mObjectQuats.length; |
|
95 |
int numGoodQuats = 0; |
|
96 |
int[] tmpQuats = new int[numQuats]; |
|
97 |
float[] tmp = new float[4]; |
|
98 |
float x = thisPos[0]; |
|
99 |
float y = thisPos[1]; |
|
100 |
float z = thisPos[2]; |
|
101 |
final float MAX_ERROR = 0.01f; |
|
102 |
|
|
103 |
for(int q=0; q<numQuats; q++) |
|
104 |
{ |
|
105 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,mObjectQuats[q]); |
|
106 |
|
|
107 |
float dx = tmp[0] - x; |
|
108 |
float dy = tmp[1] - y; |
|
109 |
float dz = tmp[2] - z; |
|
110 |
float err = dx*dx + dy*dy + dz*dz; |
|
111 |
|
|
112 |
if( err < MAX_ERROR ) |
|
113 |
{ |
|
114 |
numGoodQuats++; |
|
115 |
tmpQuats[q] = 1; |
|
116 |
} |
|
117 |
} |
|
118 |
|
|
119 |
int[] ret = new int[numGoodQuats]; |
|
120 |
int index = 0; |
|
121 |
|
|
122 |
for(int q=0; q<numQuats; q++) |
|
123 |
if( tmpQuats[q]==1 ) ret[index++] = q; |
|
124 |
|
|
125 |
return ret; |
|
126 |
} |
|
127 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseCyclicPerm2.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.library.helpers.QuatHelper; |
|
13 |
import org.distorted.library.type.Static4D; |
|
14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
public class PhaseCyclicPerm2 extends PhaseMitm |
|
19 |
{ |
|
20 |
public PhaseCyclicPerm2(SolvedObject object, int cubit, int quat) |
|
21 |
{ |
|
22 |
super(object); |
|
23 |
|
|
24 |
Static4D[] objectQuats = object.getQuats(); |
|
25 |
Static4D q = objectQuats[quat]; |
|
26 |
double alpha = 2*Math.acos(q.get3()); |
|
27 |
double numTurns = 2*Math.PI / alpha; |
|
28 |
mNumCubitsInThisPhase = (int)(numTurns+0.5f); |
|
29 |
|
|
30 |
mCubitGroups = new int[1][mNumCubitsInThisPhase]; |
|
31 |
mNumGroups = 1; |
|
32 |
|
|
33 |
float[][] positions = object.getCubitPositions(); |
|
34 |
float[] pos = positions[cubit]; |
|
35 |
float x = pos[0]; |
|
36 |
float y = pos[1]; |
|
37 |
float z = pos[2]; |
|
38 |
|
|
39 |
float[] tmp = new float[4]; |
|
40 |
|
|
41 |
mCubitGroups[0][0] = cubit; |
|
42 |
|
|
43 |
for(int c=1; c<mNumCubitsInThisPhase; c++) |
|
44 |
{ |
|
45 |
QuatHelper.rotateVectorByQuat(tmp,x,y,z,1,q); |
|
46 |
x = tmp[0]; |
|
47 |
y = tmp[1]; |
|
48 |
z = tmp[2]; |
|
49 |
|
|
50 |
mCubitGroups[0][c] = whichPosIsThis(positions,tmp); |
|
51 |
} |
|
52 |
} |
|
53 |
|
|
54 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
55 |
|
|
56 |
private int whichPosIsThis(float[][] positions, float[] pos) |
|
57 |
{ |
|
58 |
int numPos = positions.length; |
|
59 |
float minErr = Float.MAX_VALUE; |
|
60 |
int ret=-1; |
|
61 |
|
|
62 |
for(int i=0; i<numPos; i++) |
|
63 |
{ |
|
64 |
float[] curr = positions[i]; |
|
65 |
float dx = curr[0] - pos[0]; |
|
66 |
float dy = curr[1] - pos[1]; |
|
67 |
float dz = curr[2] - pos[2]; |
|
68 |
|
|
69 |
float err = dx*dx + dy*dy + dz*dz; |
|
70 |
|
|
71 |
if( err < minErr ) |
|
72 |
{ |
|
73 |
minErr = err; |
|
74 |
ret = i; |
|
75 |
} |
|
76 |
} |
|
77 |
|
|
78 |
return ret; |
|
79 |
} |
|
80 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseMitm.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
|
13 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
14 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
15 |
|
|
16 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17 |
|
|
18 |
abstract public class PhaseMitm extends Phase |
|
19 |
{ |
|
20 |
private final static int MAX_MEMORY = 6*1024*1024; // 6MB max for the MitM table |
|
21 |
private final static double MAX_SEARCH = 10000000.0; // max 10mln positions back-searched |
|
22 |
|
|
23 |
private boolean[] mSolved; |
|
24 |
private int[] mWhichSubphase; |
|
25 |
private int mForwardDepth, mBackwardDepth; |
|
26 |
|
|
27 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
28 |
|
|
29 |
PhaseMitm(SolvedObject object) |
|
30 |
{ |
|
31 |
super(object); |
|
32 |
} |
|
33 |
|
|
34 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
35 |
// Only attempt to find solutions which are not longer than maxlen; if not found, return null. |
|
36 |
// Otherwise, return an array of moves; each move is an index to the MaveTable (see branchingFactor!) |
|
37 |
// |
|
38 |
// Algorithm: |
|
39 |
// Meet in the Middle: first, do a depth-first search and remember each position in a table; depth of |
|
40 |
// this search - until we fill out no more than MAX_MEMORY in the table. |
|
41 |
// Then, from each end position (in general there can be many because in many phases there are many |
|
42 |
// valid endQuats for a given cubit) do a back-search and try to reach any of the positions from the |
|
43 |
// table. |
|
44 |
|
|
45 |
private int[] solve(SolvedObject object, MitmTable table, int depth) |
|
46 |
{ |
|
47 |
float tmp = ((float)(mForwardDepth*depth))/(mForwardDepth+mBackwardDepth); |
|
48 |
int tmpForward = (int)Math.ceil(tmp); |
|
49 |
int tmpBackward= depth-tmpForward; |
|
50 |
|
|
51 |
table.build(object,tmpForward); |
|
52 |
return table.tryReaching(object,mTargetQuats,tmpBackward,tmpForward); |
|
53 |
} |
|
54 |
|
|
55 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
56 |
|
|
57 |
private int prepareForSubPhase(SolvedObject object, MitmTable table) |
|
58 |
{ |
|
59 |
table.prepareForSubPhase(mTargetQuats); |
|
60 |
int bytesPerEntry = table.getBytesPerEntry(); |
|
61 |
int branchingFactor = object.getBranchingFactor(); |
|
62 |
|
|
63 |
mForwardDepth = computeForwardDepth(bytesPerEntry,branchingFactor); |
|
64 |
mBackwardDepth = computeBackwardDepth(branchingFactor); |
|
65 |
|
|
66 |
return mForwardDepth+mBackwardDepth; |
|
67 |
} |
|
68 |
|
|
69 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
70 |
|
|
71 |
private int computeForwardDepth(int bytesPerEntry, int branchingFactor) |
|
72 |
{ |
|
73 |
int numEntries = MAX_MEMORY/bytesPerEntry; |
|
74 |
double maxDepth = Math.log(numEntries) / Math.log(branchingFactor); |
|
75 |
return (int)maxDepth; |
|
76 |
} |
|
77 |
|
|
78 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
79 |
// how deep we can search our tree of moves 'backward' (from any one of the positions described by |
|
80 |
// 'endQuats') |
|
81 |
|
|
82 |
private int computeBackwardDepth(int branchingFactor) |
|
83 |
{ |
|
84 |
int multiplier = mTargetQuats.computeNumCombinations(); |
|
85 |
double maxDepth = Math.log(MAX_SEARCH/multiplier) / Math.log(branchingFactor); |
|
86 |
return (int)maxDepth; |
|
87 |
} |
|
88 |
|
|
89 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
90 |
// Find solution and modify the non-null initQuats to match the situation after applying it. |
|
91 |
|
|
92 |
private int[] findSol(SolvedObject object, MitmTable table, int depth) |
|
93 |
{ |
|
94 |
int[] s = solve(object,table,depth); |
|
95 |
|
|
96 |
if( s!=null ) |
|
97 |
{ |
|
98 |
int len = s.length; |
|
99 |
for(int m=1; m<len; m++) object.makeMove(s[m]); |
|
100 |
} |
|
101 |
|
|
102 |
return s; |
|
103 |
} |
|
104 |
|
|
105 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
106 |
|
|
107 |
@Override |
|
108 |
public void prepareForSubphases() |
|
109 |
{ |
|
110 |
mSolved = new boolean[mNumGroups]; |
|
111 |
mWhichSubphase = new int[mNumCubits]; |
|
112 |
|
|
113 |
for(int c=0; c<mNumCubits; c++) mWhichSubphase[c] = whichSubPhase(c); |
|
114 |
for(int s=0; s<mNumGroups; s++) mSolved[s] = false; |
|
115 |
} |
|
116 |
|
|
117 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
118 |
// a) find solution moves which take us from 'initQuats' position to a position which satisfies the |
|
119 |
// 'endQuats' criteria |
|
120 |
// b) overwrite 'initQuats' with the found position |
|
121 |
// c) return solution moves |
|
122 |
// |
|
123 |
// Of course this works only if there exists a solution with reasonable length (10 moves?) so we |
|
124 |
// need to define our phases accurately. |
|
125 |
// |
|
126 |
// initQuats: quats of the cubits at the start of the phase. Index table to mObjectQuats. |
|
127 |
// endQuats: describes what the quats should be at the end of the phase. |
|
128 |
// If endQuat[i]==null, then this mean we do not care about the state of cubit i. |
|
129 |
// Otherwise, the cubit must end up in state described by one of the ints from array 'endQuats[i]'. |
|
130 |
// |
|
131 |
// Here we try to find a single solution in one phase, i.e. solve at once all 'endQuats'. |
|
132 |
// (example: the white cross phase of the beginner's 3x3 - all four edges solved at once) |
|
133 |
|
|
134 |
@Override |
|
135 |
public int[] findSolution(SolvedObject object, MitmTable table) |
|
136 |
{ |
|
137 |
int maxdepth = prepareForSubPhase(object,table); |
|
138 |
|
|
139 |
for(int l=0; l<=maxdepth; l++) |
|
140 |
{ |
|
141 |
int[] ret = findSol(object,table,l); |
|
142 |
if( ret!=null ) return ret; |
|
143 |
} |
|
144 |
|
|
145 |
return null; |
|
146 |
} |
|
147 |
|
|
148 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
149 |
|
|
150 |
@Override |
|
151 |
public boolean solveAnySubphase( SolvedObject object, MitmTable table, int[][] solution, int subPhase) |
|
152 |
{ |
|
153 |
int maxDepth = 0; |
|
154 |
TargetQuats tmp = new TargetQuats(mTargetQuats); |
|
155 |
|
|
156 |
for( int d=0; d<=maxDepth; d++) |
|
157 |
for(int g=0; g<mNumGroups; g++) |
|
158 |
if( !mSolved[g] ) |
|
159 |
{ |
|
160 |
for(int q=0; q<mNumCubits; q++) |
|
161 |
{ |
|
162 |
// -1 means that the cubit doesn't belong to the current phase. Cubits belonging to |
|
163 |
// the next phase already have their targetQuats set to null (see Phase.setTargetQuats) |
|
164 |
// Here we set to null (mark that we do not care about) the quats of all cubits which |
|
165 |
// belong to the current phase and haven't been solved yet (except the current subphase!). |
|
166 |
int sp = mWhichSubphase[q]; |
|
167 |
mTargetQuats.set( (sp==-1 || sp==g || mSolved[sp]) ? tmp : null , q); |
|
168 |
} |
|
169 |
|
|
170 |
maxDepth = prepareForSubPhase(object,table); |
|
171 |
solution[subPhase] = findSol(object,table,d); |
|
172 |
|
|
173 |
if( solution[subPhase]!=null ) |
|
174 |
{ |
|
175 |
mTargetQuats.set(tmp); |
|
176 |
mSolved[g] = true; |
|
177 |
return true; |
|
178 |
} |
|
179 |
} |
|
180 |
|
|
181 |
mTargetQuats.set(tmp); |
|
182 |
return false; |
|
183 |
} |
|
184 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseNotCyclic.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
13 |
|
|
14 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
15 |
|
|
16 |
public class PhaseNotCyclic extends PhaseMitm |
|
17 |
{ |
|
18 |
public PhaseNotCyclic(SolvedObject object, int[][] cubitgroups) |
|
19 |
{ |
|
20 |
super(object); |
|
21 |
|
|
22 |
mCubitGroups = cubitgroups; |
|
23 |
mNumGroups = cubitgroups.length; |
|
24 |
|
|
25 |
int numCubits = 0; |
|
26 |
for(int g=0; g<mNumGroups; g++) numCubits += mCubitGroups[g].length; |
|
27 |
|
|
28 |
mNumCubitsInThisPhase = numCubits; |
|
29 |
} |
|
30 |
} |
src/main/java/org/distorted/objectlib/algphases/PhaseRegex.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.algphases; |
|
11 |
|
|
12 |
import org.distorted.objectlib.algsolvers.MitmTable; |
|
13 |
import org.distorted.objectlib.algsolvers.MoveRegex; |
|
14 |
import org.distorted.objectlib.algsolvers.SolvedObject; |
|
15 |
import org.distorted.objectlib.algsolvers.TargetQuats; |
|
16 |
|
|
17 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
18 |
|
|
19 |
public class PhaseRegex extends Phase |
|
20 |
{ |
|
21 |
private final MoveRegex mRegex; |
|
22 |
private final boolean[] mSolved; |
|
23 |
private final int[][] mMoves; |
|
24 |
private final int[][] mBasicAngles; |
|
25 |
|
|
26 |
private int[] mWhichSubphase; |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
public PhaseRegex(SolvedObject object, String regex, int[][] cubitgroups) |
|
31 |
{ |
|
32 |
super(object); |
|
33 |
|
|
34 |
mCubitGroups = cubitgroups; |
|
35 |
mNumGroups = cubitgroups.length; |
|
36 |
mRegex = new MoveRegex(object,regex); |
|
37 |
mMoves = object.getMoveTable(); |
|
38 |
mBasicAngles = object.getBasicAngles(); |
|
39 |
|
|
40 |
int numCubits = 0; |
|
41 |
for(int g=0; g<mNumGroups; g++) numCubits += mCubitGroups[g].length; |
|
42 |
|
|
43 |
mNumCubitsInThisPhase = numCubits; |
|
44 |
|
|
45 |
mSolved = new boolean[mNumGroups]; |
|
46 |
} |
|
47 |
|
|
48 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
49 |
|
|
50 |
private int findMove(int ax, int row, int angle) |
|
51 |
{ |
|
52 |
int numMoves = mMoves.length; |
|
53 |
|
|
54 |
for(int m=0; m<numMoves; m++) |
|
55 |
{ |
|
56 |
int[] move = mMoves[m]; |
|
57 |
|
|
58 |
if( move[0]==ax && move[1]==row && move[2]==angle ) |
|
59 |
return m; |
|
60 |
} |
|
61 |
|
|
62 |
return -1; |
|
63 |
} |
|
64 |
|
|
65 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
66 |
|
|
67 |
private int[] collapseMoves(int[] moves, int start, int end) |
|
68 |
{ |
|
69 |
int numCut = end-start; |
|
70 |
int len = moves.length; |
|
71 |
int[] ret = new int[len-numCut]; |
|
72 |
ret[0] = len-numCut-1; |
|
73 |
int index=1; |
|
74 |
|
|
75 |
for(int i=1; i<start; i++) ret[index++] = moves[i]; |
|
76 |
for(int i=end; i<len; i++) ret[index++] = moves[i]; |
|
77 |
|
|
78 |
return ret; |
|
79 |
} |
|
80 |
|
|
81 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
82 |
|
|
83 |
private int[] simplifyOnce(int[] moves) |
|
84 |
{ |
|
85 |
int len = moves.length; |
|
86 |
int start, end; |
|
87 |
|
|
88 |
for(start=1; start<len; start++) |
|
89 |
{ |
|
90 |
int[] m1 = mMoves[moves[start]]; |
|
91 |
int totalAngle = m1[2]; |
|
92 |
int ax = m1[0]; |
|
93 |
int row= m1[1]; |
|
94 |
|
|
95 |
for(end=start+1; end<len; end++) |
|
96 |
{ |
|
97 |
int[] m2 = mMoves[moves[end]]; |
|
98 |
if( ax!=m2[0] || row!=m2[1] ) break; |
|
99 |
totalAngle += m2[2]; |
|
100 |
} |
|
101 |
|
|
102 |
if( end>start+1 ) |
|
103 |
{ |
|
104 |
int basicAngle = mBasicAngles[ax][row]; |
|
105 |
totalAngle %= basicAngle; |
|
106 |
if( totalAngle> basicAngle/2 ) totalAngle -= basicAngle; |
|
107 |
if( totalAngle<-basicAngle/2 ) totalAngle += basicAngle; |
|
108 |
|
|
109 |
if( totalAngle==0 ) |
|
110 |
{ |
|
111 |
return collapseMoves(moves,start,end); |
|
112 |
} |
|
113 |
else |
|
114 |
{ |
|
115 |
moves[start] = findMove(ax,row,totalAngle); |
|
116 |
return collapseMoves(moves,start+1,end); |
|
117 |
} |
|
118 |
} |
|
119 |
} |
|
120 |
|
|
121 |
return moves; |
|
122 |
} |
|
123 |
|
|
124 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
125 |
|
|
126 |
private int[] simplify(int[] moves) |
|
127 |
{ |
|
128 |
int lenB, lenA; |
|
129 |
|
|
130 |
do |
|
131 |
{ |
|
132 |
lenB = moves.length; |
|
133 |
moves = simplifyOnce(moves); |
|
134 |
lenA = moves.length; |
|
135 |
} |
|
136 |
while(lenB>lenA); |
|
137 |
|
|
138 |
return moves; |
|
139 |
} |
|
140 |
|
|
141 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
142 |
|
|
143 |
public void prepareForSubphases() |
|
144 |
{ |
|
145 |
mWhichSubphase = new int[mNumCubits]; |
|
146 |
|
|
147 |
for(int c=0; c<mNumCubits; c++) mWhichSubphase[c] = whichSubPhase(c); |
|
148 |
for(int s=0; s<mNumGroups; s++) mSolved[s] = false; |
|
149 |
} |
|
150 |
|
|
151 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
152 |
// take the object, the regex and try to reach one of the mEndQuats |
|
153 |
|
|
154 |
public int[] findSolution(SolvedObject object, MitmTable table) |
|
155 |
{ |
|
156 |
int[] moveSeq = mRegex.getFirst(); |
|
157 |
int[] quats = object.getCopiedCubitQuats(); |
|
158 |
|
|
159 |
do |
|
160 |
{ |
|
161 |
int numMoves = (moveSeq==null ? 0 : moveSeq.length); |
|
162 |
for(int m=1; m<numMoves; m++) object.makeMove(moveSeq[m]); |
|
163 |
int[] qts = object.getCubitQuats(); |
|
164 |
boolean solved = mTargetQuats.matchesQuats(qts); |
|
165 |
object.setUpStartingQuats(quats); |
|
166 |
if( solved ) return simplify(moveSeq); |
|
167 |
moveSeq = mRegex.getNext(); |
|
168 |
} |
|
169 |
while( moveSeq!=null ); |
|
170 |
|
|
171 |
return null; |
|
172 |
} |
|
173 |
|
|
174 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
175 |
|
|
176 |
public boolean solveAnySubphase(SolvedObject object, MitmTable table, int[][] solution, int solIndex) |
|
177 |
{ |
|
178 |
TargetQuats tmp = new TargetQuats(mTargetQuats); |
|
179 |
|
|
180 |
for(int g=0; g<mNumGroups; g++) |
|
181 |
if( !mSolved[g] ) |
|
182 |
{ |
|
183 |
for(int q=0; q<mNumCubits; q++) |
|
184 |
{ |
|
185 |
// -1 means that the cubit belongs to the previous (or next) phase. Cubits belonging to the |
|
186 |
// next phase already have their endQuats set to null (see PhasedSolver.figureOutEndQuatIndices) |
|
187 |
// Here we set to null (i.e. - mark that we do not care about) the quats of all cubits which |
|
188 |
// belong to the current phase and haven't been solved yet (except the current subphase!). |
|
189 |
int sp = mWhichSubphase[q]; |
|
190 |
mTargetQuats.set( (sp==-1 || sp==g || mSolved[sp]) ? tmp : null , q); |
|
191 |
} |
|
192 |
|
|
193 |
solution[solIndex] = findSolution(object,table); |
|
194 |
|
|
195 |
if( solution[solIndex]!=null ) |
|
196 |
{ |
|
197 |
mTargetQuats.set(tmp); |
|
198 |
mSolved[g] = true; |
|
199 |
return true; |
|
200 |
} |
|
201 |
} |
|
202 |
|
|
203 |
mTargetQuats.set(tmp); |
|
204 |
return false; |
|
205 |
} |
|
206 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MitmTable.java | ||
---|---|---|
11 | 11 |
|
12 | 12 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
13 | 13 |
|
14 |
public class MitmTable
|
|
14 |
class MitmTable |
|
15 | 15 |
{ |
16 | 16 |
private final int mBitsPerQuat; |
17 | 17 |
private final int mNumCubits; |
... | ... | |
24 | 24 |
|
25 | 25 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
26 | 26 |
|
27 |
public MitmTable(int numCubits, int numQuats)
|
|
27 |
MitmTable(int numCubits, int numQuats) |
|
28 | 28 |
{ |
29 | 29 |
mBuildDepth= -1; |
30 | 30 |
mNumCubits = numCubits; |
... | ... | |
64 | 64 |
|
65 | 65 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
66 | 66 |
|
67 |
public static String getQuatString(int[] quats)
|
|
67 |
static String getQuatString(int[] quats) |
|
68 | 68 |
{ |
69 | 69 |
StringBuilder sb = new StringBuilder(); |
70 | 70 |
|
... | ... | |
79 | 79 |
|
80 | 80 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
81 | 81 |
|
82 |
public static String getMultiQuatString(int[][] quats)
|
|
82 |
static String getMultiQuatString(int[][] quats) |
|
83 | 83 |
{ |
84 | 84 |
StringBuilder sb = new StringBuilder(); |
85 | 85 |
|
... | ... | |
102 | 102 |
|
103 | 103 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
104 | 104 |
|
105 |
public static String getSigString(byte[] sig)
|
|
105 |
static String getSigString(byte[] sig) |
|
106 | 106 |
{ |
107 | 107 |
StringBuilder sb = new StringBuilder(); |
108 | 108 |
|
... | ... | |
117 | 117 |
|
118 | 118 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
119 | 119 |
|
120 |
public int getBytesPerEntry()
|
|
120 |
int getBytesPerEntry() |
|
121 | 121 |
{ |
122 | 122 |
return mBytesPerEntry; |
123 | 123 |
} |
124 | 124 |
|
125 | 125 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
126 | 126 |
|
127 |
public void prepareForSubPhase(TargetQuats quats)
|
|
127 |
void prepareForSubPhase(TargetQuats quats) |
|
128 | 128 |
{ |
129 | 129 |
int numUsedCubits = quats.computeUsedCubitTable(mUseCubit); |
130 | 130 |
double numBytes = numUsedCubits*mBitsPerQuat/8.0; |
... | ... | |
134 | 134 |
|
135 | 135 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
136 | 136 |
|
137 |
public void build(SolvedObject object, int depth)
|
|
137 |
void build(SolvedObject object, MoveProvider provider, int depth)
|
|
138 | 138 |
{ |
139 | 139 |
if( mBuildDepth<depth ) |
140 | 140 |
{ |
141 |
int branchingFactor = object.getBranchingFactor(); |
|
142 | 141 |
mData.clear(); |
143 |
buildRecursive(object,branchingFactor,-1,depth);
|
|
142 |
buildRecursive(object,provider,-1,depth);
|
|
144 | 143 |
mBuildDepth = depth; |
145 | 144 |
} |
146 | 145 |
} |
147 | 146 |
|
147 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
148 |
|
|
149 |
private void buildRecursive(SolvedObject object, MoveProvider provider, int previousMove, int depth) |
|
150 |
{ |
|
151 |
int[] quats = object.getCubitQuats(); |
|
152 |
byte[] signature = pack(quats); |
|
153 |
mData.add(signature); |
|
154 |
|
|
155 |
if( depth>0 ) |
|
156 |
{ |
|
157 |
int pos = provider.getPosition(); |
|
158 |
int mv = provider.firstPointer(previousMove); |
|
159 |
int[] move = provider.getCurrent(); |
|
160 |
|
|
161 |
while( move!=null ) |
|
162 |
{ |
|
163 |
for(int m : move) object.makeMove(m); |
|
164 |
buildRecursive(object,provider,mv,depth-1); |
|
165 |
for(int m : move) object.backMove(m); |
|
166 |
mv = provider.nextPointer(previousMove); |
|
167 |
move = provider.getCurrent(); |
|
168 |
} |
|
169 |
|
|
170 |
provider.setPosition(pos); |
|
171 |
} |
|
172 |
} |
|
173 |
|
|
148 | 174 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
149 | 175 |
// Having built the MiTM table, try to reach it working backwards from each of the positions |
150 | 176 |
// described by 'endQuats'. |
... | ... | |
155 | 181 |
// {0} means solution found and it's empty (position already solved) |
156 | 182 |
// {2,1,3} means the solution is 2 moves long, and the indices of moves to make are 1 and 3. |
157 | 183 |
|
158 |
public int[] tryReaching(SolvedObject object, TargetQuats target, int lenb, int lenf)
|
|
184 |
int[] tryReaching(SolvedObject object, MoveProvider provider, TargetQuats target, int lenb, int lenf)
|
|
159 | 185 |
{ |
160 |
int branching = object.getBranchingFactor(); |
|
161 | 186 |
int[] backward = new int[lenb]; |
162 | 187 |
int[] rem = object.getCopiedCubitQuats(); |
163 | 188 |
int[] quats = target.getFirst(); |
... | ... | |
165 | 190 |
do |
166 | 191 |
{ |
167 | 192 |
object.setUpStartingQuats(quats); |
168 |
byte[] reached = tryReachingRecursive(object,branching,lenb,backward);
|
|
193 |
byte[] reached = tryReachingRecursive(object,provider,lenb,backward);
|
|
169 | 194 |
|
170 | 195 |
if( reached!=null ) |
171 | 196 |
{ |
172 | 197 |
object.setUpStartingQuats(rem); |
173 | 198 |
int[] forward = new int[lenf]; |
174 |
int numMoves = reachForward(object,reached,forward,lenf); |
|
199 |
int numMoves = reachForward(object,provider,reached,forward,lenf);
|
|
175 | 200 |
return joinSequences(forward,numMoves,backward); |
176 | 201 |
} |
177 | 202 |
|
... | ... | |
180 | 205 |
while( quats!=null ); |
181 | 206 |
|
182 | 207 |
object.setUpStartingQuats(rem); |
208 |
|
|
183 | 209 |
return null; |
184 | 210 |
} |
185 | 211 |
|
186 | 212 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
187 | 213 |
|
188 |
private byte[] tryReachingRecursive(SolvedObject object, int branching, int len, int[] ret)
|
|
214 |
private byte[] tryReachingRecursive(SolvedObject object, MoveProvider provider, int len, int[] ret)
|
|
189 | 215 |
{ |
190 | 216 |
int[] quats = object.getCubitQuats(); |
191 | 217 |
byte[] signature = pack(quats); |
... | ... | |
194 | 220 |
|
195 | 221 |
if( len>0 ) |
196 | 222 |
{ |
223 |
int pos = provider.getPosition(); |
|
197 | 224 |
int previousMove = len<ret.length ? ret[len] : -1; |
225 |
ret[len-1] = provider.firstPointer(previousMove); |
|
226 |
int[] move = provider.getCurrent(); |
|
198 | 227 |
|
199 |
for(int m=0; m<branching; m++) |
|
200 |
if( object.movesDontClash(m,previousMove) ) |
|
201 |
{ |
|
202 |
object.backMove(m); |
|
203 |
ret[len-1] = m; |
|
204 |
byte[] reached = tryReachingRecursive(object,branching,len-1,ret); |
|
205 |
object.makeMove(m); |
|
228 |
while( move!=null ) |
|
229 |
{ |
|
230 |
for(int m : move) object.backMove(m); |
|
231 |
byte[] reached = tryReachingRecursive(object,provider,len-1,ret); |
|
232 |
for(int m : move) object.makeMove(m); |
|
206 | 233 |
|
207 |
if( reached!=null ) return reached; |
|
234 |
if( reached!=null ) |
|
235 |
{ |
|
236 |
provider.setPosition(pos); |
|
237 |
return reached; |
|
208 | 238 |
} |
239 |
|
|
240 |
ret[len-1] = provider.nextPointer(previousMove); |
|
241 |
move = provider.getCurrent(); |
|
242 |
} |
|
243 |
provider.setPosition(pos); |
|
209 | 244 |
} |
210 | 245 |
|
211 | 246 |
return null; |
... | ... | |
213 | 248 |
|
214 | 249 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
215 | 250 |
|
216 |
private int reachForward(SolvedObject object, byte[] signature, int[] ret, int len) |
|
251 |
private int reachForward(SolvedObject object, MoveProvider provider, byte[] signature, int[] ret, int len)
|
|
217 | 252 |
{ |
218 | 253 |
int[] quats = unpack(signature); |
219 | 254 |
int[] objqs = object.getCubitQuats(); |
... | ... | |
222 | 257 |
|
223 | 258 |
if( len>0 ) |
224 | 259 |
{ |
225 |
int branching = object.getBranchingFactor(); |
|
260 |
int pos = provider.getPosition(); |
|
261 |
ret[0] = provider.firstPointer(-1); |
|
262 |
int[] move = provider.getCurrent(); |
|
226 | 263 |
|
227 |
for(int m=0; m<branching; m++)
|
|
264 |
while( move!=null )
|
|
228 | 265 |
{ |
229 |
object.makeMove(m); |
|
230 |
ret[0] = m; |
|
231 |
int numMoves = reachForwardRecursive(object,quats,ret,1,len-1); |
|
232 |
object.backMove(m); |
|
233 |
if( numMoves>=0 ) return numMoves+1; |
|
266 |
for(int m : move) object.makeMove(m); |
|
267 |
int numMoves = reachForwardRecursive(object,provider,quats,ret,1,len-1); |
|
268 |
for(int m : move) object.backMove(m); |
|
269 |
|
|
270 |
if( numMoves>=0 ) |
|
271 |
{ |
|
272 |
provider.setPosition(pos); |
|
273 |
return numMoves+1; |
|
274 |
} |
|
275 |
|
|
276 |
ret[0] = provider.nextPointer(-1); |
|
277 |
move = provider.getCurrent(); |
|
234 | 278 |
} |
279 |
provider.setPosition(pos); |
|
235 | 280 |
} |
236 | 281 |
|
237 | 282 |
System.out.println("ERROR in reachForward: returning -1"); |
... | ... | |
241 | 286 |
|
242 | 287 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
243 | 288 |
|
244 |
private int reachForwardRecursive(SolvedObject object, int[] quats, int[] ret, int index, int len) |
|
289 |
private int reachForwardRecursive(SolvedObject object, MoveProvider provider, int[] quats, int[] ret, int index, int len)
|
|
245 | 290 |
{ |
246 | 291 |
int[] objqs = object.getCubitQuats(); |
247 | 292 |
if( quatsMatch(quats,objqs) ) return 0; |
248 | 293 |
|
249 | 294 |
if( len>0 ) |
250 | 295 |
{ |
251 |
int branching = object.getBranchingFactor(); |
|
252 |
int previousM = ret[index-1]; |
|
296 |
int pos = provider.getPosition(); |
|
297 |
int previousMove = ret[index-1]; |
|
298 |
ret[index] = provider.firstPointer(previousMove); |
|
299 |
int[] move = provider.getCurrent(); |
|
253 | 300 |
|
254 |
for(int m=0; m<branching; m++) |
|
255 |
if(object.movesDontClash(m,previousM) ) |
|
256 |
{ |
|
257 |
object.makeMove(m); |
|
258 |
ret[index] = m; |
|
259 |
int numMoves = reachForwardRecursive(object,quats,ret,index+1,len-1); |
|
260 |
object.backMove(m); |
|
301 |
while( move!=null ) |
|
302 |
{ |
|
303 |
for(int m : move) object.makeMove(m); |
|
304 |
int numMoves = reachForwardRecursive(object,provider,quats,ret,index+1,len-1); |
|
305 |
for(int m : move) object.backMove(m); |
|
261 | 306 |
|
262 |
if( numMoves>=0 ) return numMoves+1; |
|
307 |
if( numMoves>=0 ) |
|
308 |
{ |
|
309 |
provider.setPosition(pos); |
|
310 |
return numMoves+1; |
|
263 | 311 |
} |
312 |
|
|
313 |
ret[index] = provider.nextPointer(previousMove); |
|
314 |
move = provider.getCurrent(); |
|
315 |
} |
|
316 |
|
|
317 |
provider.setPosition(pos); |
|
264 | 318 |
} |
265 | 319 |
|
266 | 320 |
return -1; |
... | ... | |
304 | 358 |
return ret; |
305 | 359 |
} |
306 | 360 |
|
307 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
308 |
|
|
309 |
private void buildRecursive(SolvedObject object, int branching, int previousMove, int depth) |
|
310 |
{ |
|
311 |
int[] quats = object.getCubitQuats(); |
|
312 |
byte[] signature = pack(quats); |
|
313 |
mData.add(signature); |
|
314 |
|
|
315 |
if( depth>0 ) |
|
316 |
for(int m=0; m<branching; m++) |
|
317 |
if( object.movesDontClash(m,previousMove) ) |
|
318 |
{ |
|
319 |
object.makeMove(m); |
|
320 |
buildRecursive(object,branching,m,depth-1); |
|
321 |
object.backMove(m); |
|
322 |
} |
|
323 |
} |
|
324 |
|
|
325 | 361 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
326 | 362 |
// Find index'th entry in the table 'output'; it contains 8 bits. Write 'value' to it, but only |
327 | 363 |
// its 'toBeWritten' first bits (out of the 'remaining' bits), and at offset 'offset' in the table. |
src/main/java/org/distorted/objectlib/algsolvers/MitmTableDataStructure.java | ||
---|---|---|
29 | 29 |
|
30 | 30 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
31 | 31 |
|
32 |
MitmTableDataStructure() |
|
33 |
{ |
|
34 |
mData = new HashSet<>(); |
|
35 |
} |
|
36 |
|
|
37 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
38 |
|
|
39 |
void clear() |
|
40 |
{ |
|
41 |
mData.clear(); |
|
42 |
} |
|
43 |
|
|
44 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
45 |
|
|
46 |
boolean contains(byte[] bytes) |
|
47 |
{ |
|
48 |
return mData.contains(new ByteArray(bytes)); |
|
49 |
} |
|
50 |
|
|
51 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
52 |
|
|
53 |
void add(byte[] bytes) |
|
54 |
{ |
|
55 |
mData.add(new ByteArray(bytes)); |
|
56 |
} |
|
32 |
MitmTableDataStructure() { mData = new HashSet<>(); } |
|
33 |
void clear() { mData.clear(); } |
|
34 |
boolean contains(byte[] bytes) { return mData.contains(new ByteArray(bytes)); } |
|
35 |
void add(byte[] bytes) { mData.add(new ByteArray(bytes)); } |
|
57 | 36 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MoveProvider.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 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
13 |
|
|
14 |
abstract public class MoveProvider |
|
15 |
{ |
|
16 |
protected int mNumMoves; |
|
17 |
protected int mCurrentMove; |
|
18 |
|
|
19 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
20 |
|
|
21 |
MoveProvider(int numMoves) |
|
22 |
{ |
|
23 |
mNumMoves = numMoves; |
|
24 |
mCurrentMove = 0; |
|
25 |
} |
|
26 |
|
|
27 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
28 |
|
|
29 |
int getPosition() { return mCurrentMove; } |
|
30 |
void setPosition(int pos) { mCurrentMove = pos; } |
|
31 |
|
|
32 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
33 |
|
|
34 |
abstract int firstPointer(int previousMove); |
|
35 |
abstract int nextPointer(int previousMove); |
|
36 |
abstract int[] getCurrent(); |
|
37 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MoveProviderAlgs.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 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
13 |
|
|
14 |
public class MoveProviderAlgs extends MoveProvider |
|
15 |
{ |
|
16 |
private final int[][] mAlgorithms; |
|
17 |
|
|
18 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
19 |
|
|
20 |
public MoveProviderAlgs(int[][] algorithms) |
|
21 |
{ |
|
22 |
super(algorithms.length); |
|
23 |
mAlgorithms = algorithms; |
|
24 |
} |
|
25 |
|
|
26 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
27 |
|
|
28 |
int firstPointer(int previousMove) |
|
29 |
{ |
|
30 |
mCurrentMove = 0; |
|
31 |
return 0; |
|
32 |
} |
|
33 |
|
|
34 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
35 |
|
|
36 |
int nextPointer(int previousMove) |
|
37 |
{ |
|
38 |
mCurrentMove++; |
|
39 |
if( mCurrentMove>=mNumMoves ) mCurrentMove = -1; |
|
40 |
return mCurrentMove; |
|
41 |
} |
|
42 |
|
|
43 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
44 |
|
|
45 |
int[] getCurrent() |
|
46 |
{ |
|
47 |
return mCurrentMove>=0 ? mAlgorithms[mCurrentMove] : null; |
|
48 |
} |
|
49 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MoveProviderAll.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 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
13 |
|
|
14 |
public class MoveProviderAll extends MoveProvider |
|
15 |
{ |
|
16 |
private final int[][] mMoveTable; |
|
17 |
|
|
18 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
19 |
|
|
20 |
public MoveProviderAll(int[][] moveTable) |
|
21 |
{ |
|
22 |
super(moveTable.length); |
|
23 |
mMoveTable = moveTable; |
|
24 |
} |
|
25 |
|
|
26 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
27 |
// moves clash iff they are both along the same axis and the same row |
|
28 |
|
|
29 |
private boolean movesClash(int move1, int move2) |
|
30 |
{ |
|
31 |
if( move1>=0 && move2>=0 ) |
|
32 |
{ |
|
33 |
int[] m1 = mMoveTable[move1]; |
|
34 |
int[] m2 = mMoveTable[move2]; |
|
35 |
|
|
36 |
return ( m1[0]==m2[0] && m1[1]==m2[1] ); |
|
37 |
} |
|
38 |
|
|
39 |
return false; |
|
40 |
} |
|
41 |
|
|
42 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
43 |
|
|
44 |
int firstPointer(int previousMove) |
|
45 |
{ |
|
46 |
mCurrentMove = 0; |
|
47 |
return 0; |
|
48 |
} |
|
49 |
|
|
50 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
51 |
|
|
52 |
int nextPointer(int previousMove) |
|
53 |
{ |
|
54 |
mCurrentMove++; |
|
55 |
|
|
56 |
if( mCurrentMove>=mNumMoves ) |
|
57 |
{ |
|
58 |
mCurrentMove = -1; |
|
59 |
return mCurrentMove; |
|
60 |
} |
|
61 |
|
|
62 |
while( movesClash(previousMove,mCurrentMove) ) |
|
63 |
{ |
|
64 |
mCurrentMove++; |
|
65 |
|
|
66 |
if( mCurrentMove>=mNumMoves ) |
|
67 |
{ |
|
68 |
mCurrentMove = -1; |
|
69 |
break; |
|
70 |
} |
|
71 |
} |
|
72 |
|
|
73 |
return mCurrentMove; |
|
74 |
} |
|
75 |
|
|
76 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
77 |
|
|
78 |
int[] getCurrent() |
|
79 |
{ |
|
80 |
return mCurrentMove>=0 ? new int[] { mCurrentMove } : null; |
|
81 |
} |
|
82 |
} |
src/main/java/org/distorted/objectlib/algsolvers/MoveRegex.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 // |
Also available in: Unified diff
Clean up everything.
Algorithmic MoveProviders do nto seem to work yet. (3x3 Beginner's OLL phase does not work)