package puzzle;
import static net.gnehzr.tnoodle.utils.GwtSafeUtils.azzert;
import java.util.Random;
import net.gnehzr.tnoodle.scrambles.InvalidMoveException;
import net.gnehzr.tnoodle.scrambles.AlgorithmBuilder;
import net.gnehzr.tnoodle.scrambles.AlgorithmBuilder.MergingMode;
import net.gnehzr.tnoodle.scrambles.PuzzleStateAndGenerator;
import org.timepedia.exporter.client.Export;
@Export
public class ThreeByThreeCubeFewestMovesPuzzle extends ThreeByThreeCubePuzzle {
public ThreeByThreeCubeFewestMovesPuzzle() {
super();
}
@Override
public PuzzleStateAndGenerator generateRandomMoves(Random r) {
// For fewest moves, we want to minimize the probability that the
// scramble has useful "stuff" in it. The problem with conventional
// Kociemba 2 phase solutions is that there's a pretty obvious
// orientation step, which competitors might intentionally (or even
// accidentally!) use in their solution. To lower the probability of this happening,
// we intentionally generate dumbed down solutions.
// We eventually decided to go with "Tom2", which is described by Tom
// Rokicki (https://groups.google.com/d/msg/wca-admin/vVnuhk92hqg/P5oaJJQjDQAJ):
// START TOM MESSAGE
// If we're going this direction, and the exact length isn't critical, why not combine a bunch of the
// ideas we've seen so far into something this simple:
//
// 1. Fix a set of prefix/suffix moves, say, U F R / U F R.
// 2. For a given position p, find *any* solution where that solution prefixed and suffixed with
// the appropriate moves is canonical.
//
// That's it. So we generate a random position, then find any two-phase solution g such
// that U F R g U F R is a canonical sequence, and that's our FMC scramble.
//
// The prefix/suffix will be easily recognizable and memorable and ideally finger-trick
// friendly (if it matters).
//
// Someone wanting to practice speed FMC (hehe) can make up their own scrambles just
// by manually doing the prefix/suffix thing on any existing scrambler.
//
// It does not perturb the uniformity of the random position selection.
//
// It's simple enough that it is less likely to suffer from subtle defects due to the
// perturbation of the two-phase search (unlikely those these may be).
//
// And even if the two-phase solution is short, adding U F R to the front and back makes it
// no longer be unusually short (with high probability).
// END TOM MESSAGE
// Michael Young suggested using R' U' F as our padding (https://groups.google.com/d/msg/wca-admin/vVnuhk92hqg/EzQfG_vPBgAJ):
// START MICHAEL MESSSAGE
// I think that something more like R' U' F (some sequence that
// involves a quarter-turn on all three "axes") is better because it
// guarantees at least one bad edge in every orientation; with EO-first
// options becoming more popular, "guaranteeing" that solving EO
// optimally can't be derived from the scramble is a nice thing to
// have, I think. (Someone who was both unscrupulous and lucky could
// see that R' F R doesn't affect U2/D2 EO, and therefore find out how
// to solve EO by looking at the solution ignoring the R' F R. That
// being said, it still does change things, and I like how
// finger-tricky/reversible the current prefix is.) Just my two cents,
// 'tho.
// END MICHAEL MESSSAGE
String[] scramblePrefix = AlgorithmBuilder.splitAlgorithm("R' U' F");
String[] scrambleSuffix = AlgorithmBuilder.splitAlgorithm("R' U' F");
// super.generateRandomMoves(...) will pick a random state S and find a solution:
// solution = sol_0, sol_1, ..., sol_n-1, sol_n
// We then invert that solution to create a scramble:
// scramble = sol_n' + sol_(n-1)' + ... + sol_1' + sol_0'
// We then prefix the scramble with scramblePrefix and suffix it with
// scrambleSuffix to create paddedScramble:
// paddedScramble = scramblePrefix + scramble + scrambleSuffix
// paddedScramble = scramblePrefix + (sol_n' + sol_(n-1)' + ... + sol_1' + sol_0') + scrambleSuffix
//
// We don't want any moves to cancel here, so we need to make sure that
// sol_n' doesn't cancel with the first move of scramblePrefix:
String solutionLastAxisRestriction = scramblePrefix[scramblePrefix.length - 1].substring(0, 1);
// and we need to make sure that sol_0' doesn't cancel with the first move of
// scrambleSuffix:
String solutionFirstAxisRestriction = scrambleSuffix[0].substring(0, 1);
PuzzleStateAndGenerator psag = super.generateRandomMoves(r, solutionFirstAxisRestriction, solutionLastAxisRestriction);
AlgorithmBuilder ab = new AlgorithmBuilder(this, MergingMode.NO_MERGING);
try {
ab.appendAlgorithms(scramblePrefix);
ab.appendAlgorithm(psag.generator);
ab.appendAlgorithms(scrambleSuffix);
} catch(InvalidMoveException e) {
azzert(false, e);
return null;
}
return ab.getStateAndGenerator();
}
@Override
public String getShortName() {
return "333fm";
}
@Override
public String getLongName() {
return "3x3x3 Fewest Moves";
}
}