package cs.sq12phase;
public class Search {
int[] move = new int[100];
FullCube c = null;
FullCube d = new FullCube("");
int length1;
int maxlen2;
String sol_string;
static int getNParity(int idx, int n) {
int p = 0;
for (int i=n-2; i>=0; i--) {
p ^= idx % (n-i);
idx /= (n-i);
}
return p & 1;
}
static {
Shape.init();
Square.init();
}
public String solution(FullCube c) {
this.c = c;
sol_string = null;
int shape = c.getShapeIdx();
for (length1=Shape.ShapePrun[shape]; length1<100; length1++) {
maxlen2 = Math.min(31 - length1, 17);
if (phase1(shape, Shape.ShapePrun[shape], length1, 0, -1)) {
break;
}
}
return sol_string;
}
public String solutionOpt(FullCube c, int maxl) {
this.c = c;
sol_string = null;
int shape = c.getShapeIdx();
for (length1=Shape.ShapePrunOpt[shape]; length1<=maxl; length1++) {
if (phase1Opt(shape, Shape.ShapePrunOpt[shape], length1, 0, -1)) {
break;
}
}
return sol_string;
}
boolean phase1Opt(int shape, int prunvalue, int maxl, int depth, int lm) {
if (maxl == 0) {
return isSolvedInPhase1();
}
//try each possible move. First twist;
if (lm != 0) {
int shapex = Shape.TwistMove[shape];
int prunx = Shape.ShapePrunOpt[shapex];
if (prunx < maxl) {
move[depth] = 0;
if (phase1(shapex, prunx, maxl-1, depth+1, 0)) {
return true;
}
}
}
//Try top layer
int shapex = shape;
if(lm <= 0){
int m = 0;
while (true) {
m += Shape.TopMove[shapex];
shapex = m >> 4;
m &= 0x0f;
if (m >= 12) {
break;
}
int prunx = Shape.ShapePrunOpt[shapex];
if (prunx > maxl) {
break;
} else if (prunx < maxl) {
move[depth] = m;
if (phase1(shapex, prunx, maxl-1, depth+1, 1)) {
return true;
}
}
}
}
shapex = shape;
//Try bottom layer
if(lm <= 1){
int m = 0;
while (true) {
m += Shape.BottomMove[shapex];
shapex = m >> 4;
m &= 0x0f;
if (m >= 6) {
break;
}
int prunx = Shape.ShapePrunOpt[shapex];
if (prunx > maxl) {
break;
} else if (prunx < maxl) {
move[depth] = -m;
if (phase1(shapex, prunx, maxl-1, depth+1, 2)) {
return true;
}
}
}
}
return false;
}
boolean phase1(int shape, int prunvalue, int maxl, int depth, int lm) {
if (prunvalue==0 && maxl<4) {
return maxl==0 && init2();
}
//try each possible move. First twist;
if (lm != 0) {
int shapex = Shape.TwistMove[shape];
int prunx = Shape.ShapePrun[shapex];
if (prunx < maxl) {
move[depth] = 0;
if (phase1(shapex, prunx, maxl-1, depth+1, 0)) {
return true;
}
}
}
//Try top layer
int shapex = shape;
if(lm <= 0){
int m = 0;
while (true) {
m += Shape.TopMove[shapex];
shapex = m >> 4;
m &= 0x0f;
if (m >= 12) {
break;
}
int prunx = Shape.ShapePrun[shapex];
if (prunx > maxl) {
break;
} else if (prunx < maxl) {
move[depth] = m;
if (phase1(shapex, prunx, maxl-1, depth+1, 1)) {
return true;
}
}
}
}
shapex = shape;
//Try bottom layer
if(lm <= 1){
int m = 0;
while (true) {
m += Shape.BottomMove[shapex];
shapex = m >> 4;
m &= 0x0f;
if (m >= 6) {
break;
}
int prunx = Shape.ShapePrun[shapex];
if (prunx > maxl) {
break;
} else if (prunx < maxl) {
move[depth] = -m;
if (phase1(shapex, prunx, maxl-1, depth+1, 2)) {
return true;
}
}
}
}
return false;
}
int count = 0;
Square sq = new Square();
boolean isSolvedInPhase1() {
d.copy(c);
for (int i=0; i<length1; i++) {
d.doMove(move[i]);
}
boolean isSolved = d.ul == 0x011233 && d.ur == 455677 && d.dl == 0x998bba && d.dr == 0xddcffe && d.ml == 0;
if (isSolved) {
sol_string = move2string(length1);
}
return isSolved;
}
boolean init2() {
d.copy(c);
for (int i=0; i<length1; i++) {
d.doMove(move[i]);
}
assert Shape.ShapePrun[d.getShapeIdx()] == 0;
d.getSquare(sq);
int edge = sq.edgeperm;
int corner = sq.cornperm;
int ml = sq.ml;
int prun = Math.max(Square.SquarePrun[sq.edgeperm<<1|ml], Square.SquarePrun[sq.cornperm<<1|ml]);
for (int i=prun; i<maxlen2; i++) {
if (phase2(edge, corner, sq.topEdgeFirst, sq.botEdgeFirst, ml, i, length1, 0)) {
sol_string = move2string(i + length1);
return true;
}
}
return false;
}
int[] pruncomb = new int[100];
String move2string(int len) {
//TODO whether to invert the solution or not should be set by params.
StringBuffer s = new StringBuffer();
int top = 0, bottom = 0;
for (int i=len-1; i>=0; i--) {
int val = move[i];
if (val > 0) {
val = 12 - val;
top = (val > 6) ? (val-12) : val;
} else if (val < 0) {
val = 12 + val;
bottom = (val > 6) ? (val-12) : val;
} else {
if (top == 0 && bottom == 0) {
s.append(" / ");
} else {
s.append('(').append(top).append(",").append(bottom).append(") / ");
}
top = 0;
bottom = 0;
}
}
if (top == 0 && bottom == 0) {
} else {
s.append('(').append(top).append(",").append(bottom).append(")");
}
return s.toString();
}
boolean phase2(int edge, int corner, boolean topEdgeFirst, boolean botEdgeFirst, int ml, int maxl, int depth, int lm) {
if (maxl == 0 && !topEdgeFirst && botEdgeFirst) {
assert edge==0 && corner==0 && ml==0;
return true;
}
//try each possible move. First twist;
if(lm!=0 && topEdgeFirst == botEdgeFirst) {
int edgex = Square.TwistMove[edge];
int cornerx = Square.TwistMove[corner];
if (Square.SquarePrun[edgex<<1|(1-ml)] < maxl && Square.SquarePrun[cornerx<<1|(1-ml)] < maxl) {
move[depth] = 0;
if (phase2(edgex, cornerx, topEdgeFirst, botEdgeFirst, 1-ml, maxl-1, depth+1, 0)) {
return true;
}
}
}
//Try top layer
if (lm <= 0){
boolean topEdgeFirstx = !topEdgeFirst;
int edgex = topEdgeFirstx ? Square.TopMove[edge] : edge;
int cornerx = topEdgeFirstx ? corner : Square.TopMove[corner];
int m = topEdgeFirstx ? 1 : 2;
int prun1 = Square.SquarePrun[edgex<<1|ml];
int prun2 = Square.SquarePrun[cornerx<<1|ml];
while (m < 12 && prun1 <= maxl && prun1 <= maxl) {
if (prun1 < maxl && prun2 < maxl) {
move[depth] = m;
if (phase2(edgex, cornerx, topEdgeFirstx, botEdgeFirst, ml, maxl-1, depth+1, 1)) {
return true;
}
}
topEdgeFirstx = !topEdgeFirstx;
if (topEdgeFirstx) {
edgex = Square.TopMove[edgex];
prun1 = Square.SquarePrun[edgex<<1|ml];
m += 1;
} else {
cornerx = Square.TopMove[cornerx];
prun2 = Square.SquarePrun[cornerx<<1|ml];
m += 2;
}
}
}
if (lm <= 1){
boolean botEdgeFirstx = !botEdgeFirst;
int edgex = botEdgeFirstx ? Square.BottomMove[edge] : edge;
int cornerx = botEdgeFirstx ? corner : Square.BottomMove[corner];
int m = botEdgeFirstx ? 1 : 2;
int prun1 = Square.SquarePrun[edgex<<1|ml];
int prun2 = Square.SquarePrun[cornerx<<1|ml];
while (m < (maxl > 6 ? 6 : 12) && prun1 <= maxl && prun1 <= maxl) {
if (prun1 < maxl && prun2 < maxl) {
move[depth] = -m;
if (phase2(edgex, cornerx, topEdgeFirst, botEdgeFirstx, ml, maxl-1, depth+1, 2)) {
return true;
}
}
botEdgeFirstx = !botEdgeFirstx;
if (botEdgeFirstx) {
edgex = Square.BottomMove[edgex];
prun1 = Square.SquarePrun[edgex<<1|ml];
m += 1;
} else {
cornerx = Square.BottomMove[cornerx];
prun2 = Square.SquarePrun[cornerx<<1|ml];
m += 2;
}
}
}
return false;
}
}