-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add POC for outer-grip random state big cube scrambles
- Loading branch information
Showing
2 changed files
with
129 additions
and
1 deletion.
There are no files selected for viewing
128 changes: 128 additions & 0 deletions
128
scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/OuterRandomCubePuzzle.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package org.worldcubeassociation.tnoodle.puzzle; | ||
|
||
import org.worldcubeassociation.tnoodle.scrambles.AlgorithmBuilder; | ||
import org.worldcubeassociation.tnoodle.scrambles.InvalidMoveException; | ||
import org.worldcubeassociation.tnoodle.scrambles.PuzzleStateAndGenerator; | ||
|
||
import java.util.Random; | ||
import java.util.logging.Level; | ||
|
||
public class OuterRandomCubePuzzle extends CubePuzzle { | ||
private final ThreadLocal<ThreeByThreeCubePuzzle> threeScrambler; | ||
private final ThreadLocal<TwoByTwoCubePuzzle> twoScrambler; | ||
|
||
// number of outer layers to exclude from the "thickness" scrambling process. | ||
// The current setting means that the outermost layer (the "reduction phase") | ||
// won't receive an additional 3x3 scramble and only the layers that are relevant | ||
// to centers will be scrambled. | ||
private static final int EXCLUDE_OUTER_LAYERS = 1; | ||
|
||
public OuterRandomCubePuzzle(int size) { | ||
super(size); | ||
|
||
this.threeScrambler = new ThreadLocal<ThreeByThreeCubePuzzle>() { | ||
@Override | ||
protected ThreeByThreeCubePuzzle initialValue() { | ||
return new ThreeByThreeCubePuzzle(); | ||
} | ||
}; | ||
|
||
this.twoScrambler = new ThreadLocal<TwoByTwoCubePuzzle>() { | ||
@Override | ||
protected TwoByTwoCubePuzzle initialValue() { | ||
return new TwoByTwoCubePuzzle(); | ||
} | ||
}; | ||
} | ||
|
||
@Override | ||
public String getLongName() { | ||
return super.getLongName() + " (outer-random)"; | ||
} | ||
|
||
@Override | ||
public String getShortName() { | ||
return super.getShortName() + "or"; | ||
} | ||
|
||
@Override | ||
public double getInitializationStatus() { | ||
double threeInit = this.threeScrambler.get().getInitializationStatus(); | ||
double twoInit = this.twoScrambler.get().getInitializationStatus(); | ||
|
||
return (threeInit + twoInit) / 2; | ||
} | ||
|
||
@Override | ||
public PuzzleStateAndGenerator generateRandomMoves(Random r) { | ||
AlgorithmBuilder ab = new AlgorithmBuilder(this, AlgorithmBuilder.MergingMode.CANONICALIZE_MOVES); | ||
|
||
int thickLayers = this.size / 2; | ||
|
||
for (int thickness = EXCLUDE_OUTER_LAYERS; thickness < thickLayers; thickness++) { | ||
// need to pass thickness here to determine if we need 3x3 scr | ||
// or 2x2 scr (on the innermost layer of even-numbered NxN) | ||
String rawScramble = generateOuterScramble(thickness, r); | ||
|
||
// transform the entire scramble to wide grips. This performs absolutely no sanity checks at the moment! | ||
String morphedScramble = transformScrambleToThickness(rawScramble, thickness); | ||
|
||
try { | ||
ab.appendAlgorithm(morphedScramble); | ||
} catch (InvalidMoveException e) { | ||
l.log(Level.SEVERE, "", e); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
// we take a "classic" big cube scramble sequence as reference | ||
// because there is currently no API to generate N random moves directly | ||
// (and I am too lazy to write one if we already have something that comes close) | ||
PuzzleStateAndGenerator randomMovesPsag = super.generateRandomMoves(r); | ||
String[] randomMoves = AlgorithmBuilder.splitAlgorithm(randomMovesPsag.generator); | ||
|
||
int remainingLength = this.getRandomMoveCount() - ab.getTotalCost(); | ||
|
||
for (int i = 0; i < remainingLength; i++) { | ||
try { | ||
ab.appendMove(randomMoves[i]); | ||
} catch (InvalidMoveException e) { | ||
l.log(Level.SEVERE, "", e); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
return ab.getStateAndGenerator(); | ||
} | ||
|
||
private String generateOuterScramble(int thickness, Random r) { | ||
if (this.size % 2 == 0 && thickness == (this.size / 2) - 1) { | ||
return this.twoScrambler.get().generateWcaScramble(r); | ||
} | ||
|
||
return this.threeScrambler.get().generateWcaScramble(r); | ||
} | ||
|
||
private String transformScrambleToThickness(String rawScramble, int thickness) { | ||
String[] rawMoves = AlgorithmBuilder.splitAlgorithm(rawScramble); | ||
StringBuilder transformedMoves = new StringBuilder(); | ||
|
||
// This parsing method is very hacky in that it silently assumes it only ever handles | ||
// 2x2 and 3x3 scrambles. Concepts like "Fw" (w at the end) or even "3Fw" (number at the front) | ||
// are absolutely not accounted for because we don't need them for the current generators. | ||
for (String rawMove : rawMoves) { | ||
String rawFace = String.valueOf(rawMove.charAt(0)); | ||
Face f = Face.valueOf(rawFace); | ||
|
||
String dirModifier = rawMove.substring(1).replace('\'', '3'); | ||
int dir = dirModifier.length() == 0 ? 1 : Integer.parseInt(dirModifier); | ||
|
||
CubeMove thickMove = new CubeMove(f, dir, thickness); | ||
|
||
transformedMoves.append(thickMove); | ||
transformedMoves.append(" "); | ||
} | ||
|
||
return transformedMoves.toString().trim(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters