package puzzle; import static net.gnehzr.tnoodle.utils.GwtSafeUtils.azzert; import java.util.Random; import java.util.logging.Logger; import net.gnehzr.tnoodle.scrambles.AlgorithmBuilder; import net.gnehzr.tnoodle.scrambles.AlgorithmBuilder.MergingMode; import net.gnehzr.tnoodle.scrambles.InvalidMoveException; import net.gnehzr.tnoodle.scrambles.InvalidScrambleException; import net.gnehzr.tnoodle.scrambles.PuzzleStateAndGenerator; import net.gnehzr.tnoodle.utils.EnvGetter; import cs.min2phase.Search; import cs.min2phase.Tools; import org.timepedia.exporter.client.Export; @Export public class ThreeByThreeCubePuzzle extends CubePuzzle { private static final Logger l = Logger.getLogger(ThreeByThreeCubePuzzle.class.getName()); private static final int THREE_BY_THREE_MAX_SCRAMBLE_LENGTH = 21; private static final int THREE_BY_THREE_TIMEMIN = 200; //milliseconds private static final int THREE_BY_THREE_TIMEOUT = 60*1000; //milliseconds private ThreadLocal<Search> twoPhaseSearcher = null; public ThreeByThreeCubePuzzle() { super(3); String newMinDistance = EnvGetter.getenv("TNOODLE_333_MIN_DISTANCE"); if(newMinDistance != null) { wcaMinScrambleDistance = Integer.parseInt(newMinDistance); } twoPhaseSearcher = new ThreadLocal<Search>() { protected Search initialValue() { return new Search(); }; }; } @Override protected String solveIn(PuzzleState ps, int n) { return solveIn(ps, n, null, null); } public String solveIn(PuzzleState ps, int n, String firstAxisRestriction, String lastAxisRestriction) { CubeState cs = (CubeState) ps; if(this.equals(getSolvedState())) { // TODO - apparently min2phase can't solve the solved cube return ""; } String solution = twoPhaseSearcher.get().solution(cs.toFaceCube(), n, THREE_BY_THREE_TIMEOUT, 0, 0, firstAxisRestriction, lastAxisRestriction).trim(); if("Error 7".equals(solution)) { // No solution exists for given depth return null; } else if(solution.startsWith("Error")) { // TODO - Not really sure what to do here. l.severe(solution + " while searching for solution to " + cs.toFaceCube()); azzert(false); return null; } return solution; } public PuzzleStateAndGenerator generateRandomMoves(Random r, String firstAxisRestriction, String lastAxisRestriction) { String randomState = Tools.randomCube(r); String scramble = twoPhaseSearcher.get().solution(randomState, THREE_BY_THREE_MAX_SCRAMBLE_LENGTH, THREE_BY_THREE_TIMEOUT, THREE_BY_THREE_TIMEMIN, Search.INVERSE_SOLUTION, firstAxisRestriction, lastAxisRestriction).trim(); AlgorithmBuilder ab = new AlgorithmBuilder(this, MergingMode.CANONICALIZE_MOVES); try { ab.appendAlgorithm(scramble); } catch (InvalidMoveException e) { azzert(false, new InvalidScrambleException(scramble, e)); } return ab.getStateAndGenerator(); } @Override public PuzzleStateAndGenerator generateRandomMoves(Random r) { return generateRandomMoves(r, null, null); } }