Skip to content

Commit

Permalink
Merge pull request #169 from jfly/master
Browse files Browse the repository at this point in the history
Fixes for a few bugs involving AlgorithmBuilder
  • Loading branch information
jfly committed Feb 5, 2014
2 parents 5252936 + c507673 commit b1c5075
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 21 deletions.
12 changes: 7 additions & 5 deletions scrambles/src/net/gnehzr/tnoodle/scrambles/AlgorithmBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public IndexAndMove findBestIndexForMove(String move, MergingMode mergingMode) t
}
PuzzleState newNormalizedState = newUnNormalizedState.getNormalized();

HashMap<PuzzleState, String> successors = getState().getCanonicalMovesByState();
HashMap<? extends PuzzleState, String> successors = getState().getCanonicalMovesByState();
move = null;
// Search for the right move to do to our current state in
// order to match up with newNormalizedState.
Expand Down Expand Up @@ -148,10 +148,12 @@ public IndexAndMove findBestIndexForMove(String move, MergingMode mergingMode) t
return new IndexAndMove(lastMoveIndex, null);
} else {
successors = stateBeforeLastMove.getCanonicalMovesByState();
String alternateLastMove = successors.get(stateAfterLastMoveAndNewMove);
if(alternateLastMove != null) {
// move merges with lastMove
return new IndexAndMove(lastMoveIndex, alternateLastMove);
for(PuzzleState ps : successors.keySet()) {
if(ps.equalsNormalized(stateAfterLastMoveAndNewMove)) {
String alternateLastMove = successors.get(ps);
// move merges with lastMove
return new IndexAndMove(lastMoveIndex, alternateLastMove);
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions scrambles/src/net/gnehzr/tnoodle/scrambles/Puzzle.java
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ protected String solveIn(PuzzleState ps, int n) {
}


HashMap<PuzzleState, String> movesByState = node.getCanonicalMovesByState();
HashMap<? extends PuzzleState, String> movesByState = node.getCanonicalMovesByState();
for(PuzzleState next : movesByState.keySet()) {
int moveCost = node.getMoveCost(movesByState.get(next));
int nextDistance = distance + moveCost;
Expand Down Expand Up @@ -631,7 +631,7 @@ public PuzzleState applyAlgorithm(String algorithm) throws InvalidScrambleExcept
* @return A mapping of canonical PuzzleState's to the name of
* the move that gets you to them.
*/
public final HashMap<PuzzleState, String> getCanonicalMovesByState() {
public HashMap<? extends PuzzleState, String> getCanonicalMovesByState() {
LinkedHashMap<String, ? extends PuzzleState> successorsByName =
getSuccessorsByName();
HashMap<PuzzleState, String> uniqueSuccessors =
Expand Down Expand Up @@ -739,7 +739,7 @@ public int getMoveCost(String move) {
* The move Strings may not contain spaces.
*/
public HashMap<String, ? extends PuzzleState> getScrambleSuccessors() {
return getSuccessorsByName();
return GwtSafeUtils.reverseHashMap(getCanonicalMovesByState());
}

/**
Expand Down
24 changes: 17 additions & 7 deletions scrambles/src/puzzle/CubePuzzle.java
Original file line number Diff line number Diff line change
Expand Up @@ -504,13 +504,28 @@ public String toFaceCube() {

@Override
public LinkedHashMap<String, CubeState> getSuccessorsByName() {
return getSuccessorsWithinSlice(size - 1);
return getSuccessorsWithinSlice(size - 1, true);
}

private LinkedHashMap<String, CubeState> getSuccessorsWithinSlice(int maxSlice) {
@Override
public HashMap<String, CubeState> getScrambleSuccessors() {
return getSuccessorsWithinSlice((int) (size / 2) - 1, false);
}

@Override
public HashMap<? extends PuzzleState, String> getCanonicalMovesByState() {
return GwtSafeUtils.reverseHashMap(getScrambleSuccessors());
}

private LinkedHashMap<String, CubeState> getSuccessorsWithinSlice(int maxSlice, boolean includeRedundant) {
LinkedHashMap<String, CubeState> successors = new LinkedHashMap<String, CubeState>();
for(int innerSlice = 0; innerSlice <= maxSlice; innerSlice++) {
for(Face face : Face.values()) {
boolean halfOfEvenCube = size % 2 == 0 && (innerSlice == (size / 2) - 1);
if(!includeRedundant && face.ordinal() >= 3 && halfOfEvenCube) {
// Skip turning the other halves of even sized cubes
continue;
}
int outerSlice = 0;
for(int dir = 1; dir <= 3; dir++) {
CubeMove move = new CubeMove(face, dir, innerSlice, outerSlice);
Expand All @@ -532,11 +547,6 @@ private LinkedHashMap<String, CubeState> getSuccessorsWithinSlice(int maxSlice)
return successors;
}

@Override
public HashMap<String, CubeState> getScrambleSuccessors() {
return getSuccessorsWithinSlice((int) (size / 2) - 1);
}

@Override
public boolean equals(Object other) {
return Arrays.deepEquals(image, ((CubeState) other).image);
Expand Down
4 changes: 2 additions & 2 deletions scrambles/src/puzzle/MegaminxPuzzle.java
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,9 @@ public LinkedHashMap<String, MegaminxState> getSuccessorsByName() {
HashMap<String, Face> pochmannFaceNames = new HashMap<String, Face>();
pochmannFaceNames.put("R", Face.DBR);
pochmannFaceNames.put("D", Face.D);
String[] prettyPochmannDir = new String[] { null, null, "++", "--" };
String[] prettyPochmannDir = new String[] { null, "+", "++", "--" , "-"};
for(String pochmannFaceName : pochmannFaceNames.keySet()) {
for(int dir : new int[] { 2, 3 }) {
for(int dir = 1; dir < 5; dir++) {
String move = pochmannFaceName + prettyPochmannDir[dir];

int[][] imageCopy = cloneImage(image);
Expand Down
24 changes: 21 additions & 3 deletions scrambles/test/AlgorithmBuilderTest.jy
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import tntdebug

from puzzle import CubePuzzle

from net.gnehzr.tnoodle.scrambles import PuzzlePlugins
from net.gnehzr.tnoodle.scrambles import AlgorithmBuilder
from net.gnehzr.tnoodle.scrambles.AlgorithmBuilder import MergingMode

def main():
# This test doesn't really belong here, but I don't have a better
# place for it right now.
sixes = CubePuzzle(6)
ab = AlgorithmBuilder(sixes, MergingMode.NO_MERGING)
ab.appendAlgorithm("3Dw2")
assert ab.isRedundant("3Dw2")
scrambleSuccessors = dict(sixes.getSolvedState().getScrambleSuccessors())
moves = scrambleSuccessors.keys()
assert "3Bw" not in moves
assert "3Lw" not in moves
assert "3Dw" not in moves

lazyScramblers = dict(PuzzlePlugins.getScramblers())
for puzzle, lazyScrambler in lazyScramblers.iteritems():
print "Testing redundant moves on " + puzzle
scrambler = lazyScrambler.cachedInstance()

for move in scrambler.getSolvedState().getSuccessorsByName():
ab = AlgorithmBuilder(scrambler, MergingMode.NO_MERGING)
ab.appendAlgorithm(move)
# Right now, it is true to say that for every single WCA puzzle,
# applying the same move twice is redundant.
assert ab.isRedundant(move)

if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion tmt
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@ Implementation-Version: %s
retVal = os.system("./jython %s" % absTestFile)
if retVal != 0:
print("Test %s failed with exit code %s" % (absTestFile, retVal))
sys.exit(retVal)
sys.exit(1)

def clean(self):
print('Cleaning: %s' % self.name)
Expand Down
9 changes: 9 additions & 0 deletions utils/src/net/gnehzr/tnoodle/utils/GwtSafeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,14 @@ public static void fullyReadInputStream(InputStream is, ByteArrayOutputStream by
is.close();
}
}

public static <A, B> HashMap<B, A> reverseHashMap(HashMap<A, B> map) {
HashMap<B, A> reverseMap = new HashMap<B, A>();
for(A a : map.keySet()) {
B b = map.get(a);
reverseMap.put(b, a);
}
return reverseMap;
}

}
1 change: 1 addition & 0 deletions utils/src/net/gnehzr/tnoodle/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,5 @@ public static Random getSeededRandom() {
r = new Random(seed.hashCode());
return r;
}

}

0 comments on commit b1c5075

Please sign in to comment.