Add puzzle solver for monkey madness 1 puzzle box (#6545)
* Add puzzle solver for monkey madness 1 puzzle box
This commit is contained in:
@@ -49,6 +49,10 @@ public enum InventoryID
|
||||
* Barrows reward chest inventory.
|
||||
*/
|
||||
BARROWS_REWARD(141),
|
||||
/**
|
||||
* Monkey madness puzzle box inventory.
|
||||
*/
|
||||
MONKEY_MADNESS_PUZZLE_BOX(221),
|
||||
/**
|
||||
* Chambers of Xeric chest inventory.
|
||||
*/
|
||||
|
||||
@@ -52,6 +52,7 @@ import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStarMM;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
@@ -105,11 +106,18 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean useNormalSolver = true;
|
||||
ItemContainer container = client.getItemContainer(InventoryID.PUZZLE_BOX);
|
||||
|
||||
if (container == null)
|
||||
{
|
||||
return null;
|
||||
useNormalSolver = false;
|
||||
container = client.getItemContainer(InventoryID.MONKEY_MADNESS_PUZZLE_BOX);
|
||||
|
||||
if (container == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Widget puzzleBox = client.getWidget(WidgetInfo.PUZZLE_BOX);
|
||||
@@ -123,7 +131,7 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
|
||||
String infoString = "Solving..";
|
||||
|
||||
int[] itemIds = getItemIds(container);
|
||||
int[] itemIds = getItemIds(container, useNormalSolver);
|
||||
boolean shouldCache = false;
|
||||
|
||||
if (solver != null)
|
||||
@@ -335,7 +343,7 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
if (solver == null || cachedItems == null
|
||||
|| (!shouldCache && solver.hasExceededWaitDuration() && !Arrays.equals(cachedItems, itemIds)))
|
||||
{
|
||||
solve(itemIds);
|
||||
solve(itemIds, useNormalSolver);
|
||||
shouldCache = true;
|
||||
}
|
||||
|
||||
@@ -347,7 +355,7 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
return null;
|
||||
}
|
||||
|
||||
private int[] getItemIds(ItemContainer container)
|
||||
private int[] getItemIds(ItemContainer container, boolean useNormalSolver)
|
||||
{
|
||||
int[] itemIds = new int[DIMENSION * DIMENSION];
|
||||
|
||||
@@ -364,13 +372,10 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
itemIds[items.length] = BLANK_TILE_VALUE;
|
||||
}
|
||||
|
||||
return convertToSolverFormat(itemIds);
|
||||
return convertToSolverFormat(itemIds, useNormalSolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* This depends on there being no gaps in between item ids in puzzles.
|
||||
*/
|
||||
private int[] convertToSolverFormat(int[] items)
|
||||
private int[] convertToSolverFormat(int[] items, boolean useNormalSolver)
|
||||
{
|
||||
int lowestId = Integer.MAX_VALUE;
|
||||
|
||||
@@ -393,7 +398,15 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
{
|
||||
if (items[i] != BLANK_TILE_VALUE)
|
||||
{
|
||||
convertedItems[i] = items[i] - lowestId;
|
||||
int value = items[i] - lowestId;
|
||||
|
||||
// The MM puzzle has gaps
|
||||
if (!useNormalSolver)
|
||||
{
|
||||
value /= 2;
|
||||
}
|
||||
|
||||
convertedItems[i] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -410,7 +423,7 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
System.arraycopy(items, 0, cachedItems, 0, cachedItems.length);
|
||||
}
|
||||
|
||||
private void solve(int[] items)
|
||||
private void solve(int[] items, boolean useNormalSolver)
|
||||
{
|
||||
if (solverFuture != null)
|
||||
{
|
||||
@@ -419,7 +432,15 @@ public class PuzzleSolverOverlay extends Overlay
|
||||
|
||||
PuzzleState puzzleState = new PuzzleState(items);
|
||||
|
||||
solver = new PuzzleSolver(new IDAStar(new ManhattanDistance()), puzzleState);
|
||||
if (useNormalSolver)
|
||||
{
|
||||
solver = new PuzzleSolver(new IDAStar(new ManhattanDistance()), puzzleState);
|
||||
}
|
||||
else
|
||||
{
|
||||
solver = new PuzzleSolver(new IDAStarMM(new ManhattanDistance()), puzzleState);
|
||||
}
|
||||
|
||||
solverFuture = executorService.submit(solver);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,20 +53,8 @@ public class PuzzleState
|
||||
throw new IllegalStateException("Piece array does not have the right dimensions");
|
||||
}
|
||||
|
||||
for (int i = 0; i < pieces.length; i++)
|
||||
{
|
||||
if (pieces[i] == BLANK_TILE_VALUE)
|
||||
{
|
||||
emptyPiece = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyPiece == -1)
|
||||
{
|
||||
throw new IllegalStateException("Incorrect empty piece passed in!");
|
||||
}
|
||||
|
||||
this.pieces = pieces;
|
||||
findEmptyPiece();
|
||||
}
|
||||
|
||||
private PuzzleState(PuzzleState state)
|
||||
@@ -75,6 +63,19 @@ public class PuzzleState
|
||||
this.emptyPiece = state.emptyPiece;
|
||||
}
|
||||
|
||||
private void findEmptyPiece()
|
||||
{
|
||||
for (int i = 0; i < pieces.length; i++)
|
||||
{
|
||||
if (pieces[i] == BLANK_TILE_VALUE)
|
||||
{
|
||||
this.emptyPiece = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Incorrect empty piece passed in!");
|
||||
}
|
||||
|
||||
public List<PuzzleState> computeMoves()
|
||||
{
|
||||
List<PuzzleState> moves = new ArrayList<>();
|
||||
@@ -179,4 +180,46 @@ public class PuzzleState
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public PuzzleState swap(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int val1 = getPiece(x1, y1);
|
||||
int val2 = getPiece(x2, y2);
|
||||
|
||||
if (!isValidSwap(x1, y1, x2, y2))
|
||||
{
|
||||
throw new IllegalStateException(String.format("Invalid swap: (%1$d, %2$d), (%3$d, %4$d)", x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
PuzzleState newState = new PuzzleState(this);
|
||||
|
||||
newState.pieces[y1 * DIMENSION + x1] = val2;
|
||||
newState.pieces[y2 * DIMENSION + x2] = val1;
|
||||
newState.findEmptyPiece();
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
private boolean isValidSwap(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int absX = Math.abs(x1 - x2);
|
||||
int absY = Math.abs(y1 - y2);
|
||||
|
||||
if (getPiece(x1, y1) != BLANK_TILE_VALUE && getPiece(x2, y2) != BLANK_TILE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x1 == x2 && absY == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (y1 == y2 && absX == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Steffen Hauge <steffen.oerum.hauge@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.solver;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum PuzzleSwapPattern
|
||||
{
|
||||
ROTATE_LEFT_UP(new int[]{1, -1, 0, -1, -1, -1, -1, 0}, 1, 1), //Reference point
|
||||
ROTATE_LEFT_DOWN(1, -1),
|
||||
ROTATE_RIGHT_UP(-1, 1),
|
||||
ROTATE_RIGHT_DOWN(-1, -1),
|
||||
ROTATE_UP_LEFT(new int[]{-1, 1, -1, 0, -1, -1, 0, -1}, 1 , 1), //Reference point
|
||||
ROTATE_UP_RIGHT(-1, 1),
|
||||
ROTATE_DOWN_LEFT(1, -1),
|
||||
ROTATE_DOWN_RIGHT(-1, -1),
|
||||
LAST_PIECE_ROW(new int[]{-1, -1, 0, -1, -1, 0, -1, 1}, 1, 1),
|
||||
LAST_PIECE_COLUMN(new int[]{-1, -1, -1, 0, 0, -1, 1, -1}, 1, 1),
|
||||
SHUFFLE_UP_RIGHT(new int[]{1, -1, 0, -1}, 1, 1),
|
||||
SHUFFLE_UP_LEFT(new int[]{-1, -1, 0, -1}, 1, 1),
|
||||
SHUFFLE_UP_BELOW(new int[]{-1, 1, -1, 0}, 1, 1),
|
||||
SHUFFLE_UP_ABOVE(new int[]{-1, -1, -1, 0}, 1, 1);
|
||||
|
||||
/**
|
||||
* Points used for swaps relative to locVal
|
||||
*/
|
||||
private final int[] points;
|
||||
/**
|
||||
* Modifier for X coordinate
|
||||
*/
|
||||
private final int modX;
|
||||
/**
|
||||
* Modifier for Y coordinate
|
||||
*/
|
||||
private final int modY;
|
||||
|
||||
PuzzleSwapPattern(int modX, int modY)
|
||||
{
|
||||
this(null, modX, modY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,716 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Steffen Hauge <steffen.oerum.hauge@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.solver.pathfinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.runelite.api.Point;
|
||||
import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE;
|
||||
import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern;
|
||||
import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.*;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic;
|
||||
|
||||
public class IDAStarMM extends IDAStar
|
||||
{
|
||||
private PuzzleState currentState;
|
||||
private List<PuzzleState> stateList = new ArrayList<>();
|
||||
private List<List<Integer>> validRowNumbers = new ArrayList<>();
|
||||
private List<List<Integer>> validColumnNumbers = new ArrayList<>();
|
||||
|
||||
public IDAStarMM(Heuristic heuristic)
|
||||
{
|
||||
super(heuristic);
|
||||
|
||||
//Add valid numbers for rows and columns
|
||||
validRowNumbers.add(Arrays.asList(0, 1, 2, 3, 4));
|
||||
validRowNumbers.add(Arrays.asList(6, 7, 8, 9));
|
||||
validColumnNumbers.add(Arrays.asList(5, 10, 15, 20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PuzzleState> computePath(PuzzleState root)
|
||||
{
|
||||
currentState = root;
|
||||
stateList.add(root);
|
||||
|
||||
List<PuzzleState> path = new ArrayList<>();
|
||||
|
||||
//Reduce to 4x5
|
||||
solveRow(0);
|
||||
|
||||
//Reduce to 4x4
|
||||
solveColumn();
|
||||
|
||||
//Reduce to 3x4
|
||||
solveRow(1);
|
||||
|
||||
//Remove last state
|
||||
stateList.remove(stateList.size() - 1);
|
||||
|
||||
//Pathfinder for 4x4
|
||||
path.addAll(super.computePath(currentState));
|
||||
|
||||
path.addAll(0, stateList);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void solveRow(int row)
|
||||
{
|
||||
for (int i = row; i < DIMENSION; i++)
|
||||
{
|
||||
int valTarget = row * DIMENSION + i;
|
||||
|
||||
int valCurrent = currentState.getPiece(i, row);
|
||||
|
||||
if (valCurrent != valTarget)
|
||||
{
|
||||
moveTowardsVal(valTarget, i, row, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void solveColumn()
|
||||
{
|
||||
int column = 0;
|
||||
|
||||
for (int i = column + 1; i < DIMENSION; i++)
|
||||
{
|
||||
int valTarget = column + i * DIMENSION;
|
||||
|
||||
int valCurrent = currentState.getPiece(column, i);
|
||||
|
||||
if (valCurrent != valTarget)
|
||||
{
|
||||
moveTowardsVal(valTarget, column, i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveTowardsVal(int valTarget, int x, int y, boolean rowMode)
|
||||
{
|
||||
//Not in place
|
||||
boolean reached = false;
|
||||
|
||||
while (currentState.getPiece(x, y) != valTarget)
|
||||
{
|
||||
//Find piece location
|
||||
Point locVal = findPiece(valTarget);
|
||||
Point locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
if (reached)
|
||||
{
|
||||
//Swap towards locTarget
|
||||
if (rowMode)
|
||||
{
|
||||
alignTargetX(valTarget, x, y);
|
||||
swapUpRow(valTarget, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
alignTargetY(valTarget, x, y);
|
||||
swapLeftColumn(valTarget, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int distX = locVal.getX() - locBlank.getX();
|
||||
int distY = locVal.getY() - locBlank.getY();
|
||||
int distAbsX = Math.abs(distX);
|
||||
int distAbsY = Math.abs(distY);
|
||||
|
||||
if (distX == 0)
|
||||
{
|
||||
//Same column
|
||||
if (distAbsY == 1)
|
||||
{
|
||||
//Next to
|
||||
reached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//More than 2 away, move towards on Y-axis
|
||||
if (distY >= 2)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1);
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
else if (distY <= -2)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1);
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (distY == 0)
|
||||
{
|
||||
//Same row
|
||||
if (distAbsX == 1)
|
||||
{
|
||||
//Next to
|
||||
reached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//More than 2 away, move towards on X-axis
|
||||
if (distX >= 2)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY());
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
else if (distX <= -2)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY());
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Different row and column
|
||||
if (rowMode)
|
||||
{
|
||||
//Check if already correct above
|
||||
if (locBlank.getY() - 1 == y
|
||||
&& validRowNumbers.get(y).contains(currentState.getPiece(locBlank.getX(), locBlank.getY() - 1))
|
||||
&& currentState.getPiece(locBlank.getX(), locBlank.getY() - 1) < valTarget
|
||||
&& distY <= -1)
|
||||
{
|
||||
//Move forward
|
||||
Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY());
|
||||
swap(locBlank, locSwap);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Move downwards or upwards
|
||||
if (distY >= 1)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1);
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
else if (distY <= -1)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1);
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check if already correct to the left
|
||||
if (locBlank.getX() - 1 == x
|
||||
&& validColumnNumbers.get(x).contains(currentState.getPiece(locBlank.getX() - 1, locBlank.getY()))
|
||||
&& currentState.getPiece(locBlank.getX() - 1, locBlank.getY()) < valTarget
|
||||
&& distX <= -1)
|
||||
{
|
||||
//Move down
|
||||
Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1);
|
||||
swap(locBlank, locSwap);
|
||||
continue;
|
||||
}
|
||||
|
||||
//Move right or left
|
||||
if (distX >= 1)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY());
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
else if (distX <= -1)
|
||||
{
|
||||
Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY());
|
||||
swap(locBlank, locSwap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void alignTargetX(int valTarget, int x, int y)
|
||||
{
|
||||
Point locVal = findPiece(valTarget);
|
||||
|
||||
//Check if same column
|
||||
if (locVal.getX() == x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//1 = right, -1 = left
|
||||
int direction = Integer.signum(x - locVal.getX());
|
||||
|
||||
while (locVal.getX() != x)
|
||||
{
|
||||
locVal = findPiece(valTarget);
|
||||
Point locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if aligned
|
||||
if (x - locVal.getX() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (locVal.getX() == locBlank.getX())
|
||||
{
|
||||
int diff = locBlank.getY() - locVal.getY();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Below
|
||||
Point loc1 = new Point(locBlank.getX() + direction, locBlank.getY());
|
||||
Point loc2 = new Point(loc1.getX(), loc1.getY() - 1);
|
||||
|
||||
swap(locBlank, loc1);
|
||||
swap(loc1, loc2);
|
||||
swap(loc2, locVal);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Above
|
||||
swap(locBlank, locVal);
|
||||
}
|
||||
}
|
||||
else if (locVal.getY() == locBlank.getY())
|
||||
{
|
||||
int diff = locBlank.getX() - locVal.getX();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Right
|
||||
if (direction == 1)
|
||||
{
|
||||
swap(locVal, locBlank);
|
||||
}
|
||||
else if (direction == -1)
|
||||
{
|
||||
//Check space
|
||||
if (locVal.getY() == DIMENSION - 1)
|
||||
{
|
||||
//No space below, use upper rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_LEFT_UP);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Space below, use lower rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Left
|
||||
if (direction == -1)
|
||||
{
|
||||
swap(locVal, locBlank);
|
||||
}
|
||||
else if (direction == 1)
|
||||
{
|
||||
//Check space
|
||||
if (locVal.getY() == DIMENSION - 1)
|
||||
{
|
||||
//No space below, use upper rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_RIGHT_UP);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Space below, use lower rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_RIGHT_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Swaps up until inserted into the correct place
|
||||
private void swapUpRow(int valTarget, int x, int y)
|
||||
{
|
||||
Point locVal = findPiece(valTarget);
|
||||
Point locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if already placed correct
|
||||
if (locVal.getX() == x && locVal.getY() == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if simple swap is enough
|
||||
if (locBlank.getX() == x && locBlank.getY() == y && locVal.getY() - 1 == y)
|
||||
{
|
||||
swap(locBlank, locVal);
|
||||
return;
|
||||
}
|
||||
|
||||
//Move up
|
||||
while (true)
|
||||
{
|
||||
locVal = findPiece(valTarget);
|
||||
locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if already placed correct
|
||||
if (locVal.getX() == x && locVal.getY() == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (locVal.getX() == locBlank.getX())
|
||||
{
|
||||
int diff = locBlank.getY() - locVal.getY();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Below
|
||||
|
||||
//Last piece
|
||||
if (x == DIMENSION - 1)
|
||||
{
|
||||
performSwapPattern(locBlank, locVal, LAST_PIECE_ROW);
|
||||
return;
|
||||
}
|
||||
|
||||
performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Above
|
||||
swap(locBlank, locVal);
|
||||
}
|
||||
}
|
||||
else if (locVal.getY() == locBlank.getY())
|
||||
{
|
||||
int diff = locBlank.getX() - locVal.getX();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Right
|
||||
performSwapPattern(locBlank, locVal, SHUFFLE_UP_RIGHT);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Left
|
||||
|
||||
//Don't remove correct pieces from row
|
||||
if (locVal.getY() - 1 == y)
|
||||
{
|
||||
//Swap blank to below and continue
|
||||
Point loc1 = new Point(locBlank.getX(), locBlank.getY() + 1);
|
||||
Point loc2 = new Point(loc1.getX() + 1, loc1.getY());
|
||||
|
||||
swap(locBlank, loc1);
|
||||
swap(loc1, loc2);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
performSwapPattern(locBlank, locVal, SHUFFLE_UP_LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void alignTargetY(int valTarget, int x, int y)
|
||||
{
|
||||
Point locVal = findPiece(valTarget);
|
||||
|
||||
//Check if same row
|
||||
if (locVal.getY() == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//1 = down, -1 = up
|
||||
int direction = Integer.signum(y - locVal.getY());
|
||||
|
||||
while (locVal.getY() != y)
|
||||
{
|
||||
locVal = findPiece(valTarget);
|
||||
Point locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if aligned
|
||||
if (y - locVal.getY() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (locVal.getY() == locBlank.getY())
|
||||
{
|
||||
int diff = locBlank.getX() - locVal.getX();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Right
|
||||
Point loc1 = new Point(locBlank.getX(), locBlank.getY() + direction);
|
||||
Point loc2 = new Point(loc1.getX() - 1, loc1.getY());
|
||||
|
||||
swap(locBlank, loc1);
|
||||
swap(loc1, loc2);
|
||||
swap(loc2, locVal);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Left
|
||||
swap(locBlank, locVal);
|
||||
}
|
||||
}
|
||||
else if (locVal.getX() == locBlank.getX())
|
||||
{
|
||||
int diff = locBlank.getY() - locVal.getY();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Below
|
||||
if (direction == 1)
|
||||
{
|
||||
swap(locVal, locBlank);
|
||||
}
|
||||
else if (direction == -1)
|
||||
{
|
||||
//Check space
|
||||
if (locVal.getX() == DIMENSION - 1)
|
||||
{
|
||||
//No space to the right, use left rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_UP_LEFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Space to the right, use right rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Above
|
||||
if (direction == -1)
|
||||
{
|
||||
swap(locVal, locBlank);
|
||||
}
|
||||
else if (direction == 1)
|
||||
{
|
||||
//Check space
|
||||
if (locVal.getX() == DIMENSION - 1)
|
||||
{
|
||||
//No space to the right, use left rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_DOWN_LEFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Space to the right, use right rotate
|
||||
performSwapPattern(locBlank, locVal, ROTATE_DOWN_RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Swaps left until inserted into the correct place
|
||||
private void swapLeftColumn(int valTarget, int x, int y)
|
||||
{
|
||||
Point locVal = findPiece(valTarget);
|
||||
Point locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if already placed correct
|
||||
if (locVal.getX() == x && locVal.getY() == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if simple swap is enough
|
||||
if (locBlank.getX() == x && locBlank.getY() == y && locVal.getX() - 1 == x)
|
||||
{
|
||||
swap(locBlank, locVal);
|
||||
return;
|
||||
}
|
||||
|
||||
//Move left
|
||||
while (true)
|
||||
{
|
||||
locVal = findPiece(valTarget);
|
||||
locBlank = findPiece(BLANK_TILE_VALUE);
|
||||
|
||||
//Check if already placed correct
|
||||
if (locVal.getX() == x && locVal.getY() == y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (locVal.getX() == locBlank.getX())
|
||||
{
|
||||
int diff = locBlank.getY() - locVal.getY();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Below
|
||||
performSwapPattern(locBlank, locVal, SHUFFLE_UP_BELOW);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Above
|
||||
|
||||
//Don't remove correct pices from row
|
||||
if (locVal.getX() - 1 == x)
|
||||
{
|
||||
//Swap blank to right and continue
|
||||
Point loc1 = new Point(locBlank.getX() + 1, locBlank.getY());
|
||||
Point loc2 = new Point(loc1.getX(), loc1.getY() + 1);
|
||||
|
||||
swap(locBlank, loc1);
|
||||
swap(loc1, loc2);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
performSwapPattern(locBlank, locVal, SHUFFLE_UP_ABOVE);
|
||||
}
|
||||
}
|
||||
else if (locVal.getY() == locBlank.getY())
|
||||
{
|
||||
int diff = locBlank.getX() - locVal.getX();
|
||||
if (diff == 1)
|
||||
{
|
||||
//Right
|
||||
|
||||
//Last piece
|
||||
if (y == DIMENSION - 1)
|
||||
{
|
||||
performSwapPattern(locBlank, locVal, LAST_PIECE_COLUMN);
|
||||
return;
|
||||
}
|
||||
|
||||
performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN);
|
||||
}
|
||||
else if (diff == -1)
|
||||
{
|
||||
//Left
|
||||
swap(locBlank, locVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(Point p1, Point p2)
|
||||
{
|
||||
PuzzleState newState = currentState.swap(p1.getX(), p1.getY(), p2.getX(), p2.getY());
|
||||
|
||||
currentState = newState;
|
||||
stateList.add(newState);
|
||||
}
|
||||
|
||||
private Point findPiece(int val)
|
||||
{
|
||||
for (int x = 0; x < DIMENSION; x++)
|
||||
{
|
||||
for (int y = 0; y < DIMENSION; y++)
|
||||
{
|
||||
if (currentState.getPiece(x, y) == val)
|
||||
{
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This should never happen
|
||||
throw new IllegalStateException("Piece wasn't found!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes locBlank is first point for swap and locVal is last point for swap
|
||||
*
|
||||
* swap(locBlank, loc1);
|
||||
* swap(loc1, loc2);
|
||||
* swap(loc2, locVal);
|
||||
*/
|
||||
private void performSwapPattern(Point locBlank, Point locVal, PuzzleSwapPattern pattern)
|
||||
{
|
||||
int[] offsets;
|
||||
switch (pattern)
|
||||
{
|
||||
case ROTATE_LEFT_UP:
|
||||
case ROTATE_RIGHT_UP:
|
||||
case ROTATE_RIGHT_DOWN:
|
||||
case ROTATE_LEFT_DOWN:
|
||||
offsets = ROTATE_LEFT_UP.getPoints();
|
||||
break;
|
||||
case ROTATE_UP_LEFT:
|
||||
case ROTATE_UP_RIGHT:
|
||||
case ROTATE_DOWN_LEFT:
|
||||
case ROTATE_DOWN_RIGHT:
|
||||
offsets = ROTATE_UP_LEFT.getPoints();
|
||||
break;
|
||||
default:
|
||||
offsets = pattern.getPoints();
|
||||
}
|
||||
|
||||
if (offsets == null || offsets.length % 2 == 1)
|
||||
{
|
||||
// This should never happen
|
||||
throw new IllegalStateException("Unexpected points given in pattern!");
|
||||
}
|
||||
|
||||
int modX = pattern.getModX();
|
||||
int modY = pattern.getModY();
|
||||
|
||||
ArrayList<Point> points = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < offsets.length; i += 2)
|
||||
{
|
||||
int x = locVal.getX() + modX * offsets[i];
|
||||
int y = locVal.getY() + modY * offsets[i + 1];
|
||||
|
||||
points.add(new Point(x, y));
|
||||
}
|
||||
|
||||
// Add locVal as last point
|
||||
points.add(locVal);
|
||||
|
||||
if (pattern != LAST_PIECE_ROW && pattern != LAST_PIECE_COLUMN)
|
||||
{
|
||||
Point start = locBlank;
|
||||
for (Point p : points)
|
||||
{
|
||||
swap(start, p);
|
||||
start = p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Point loc1 = points.get(0);
|
||||
Point loc2 = points.get(1);
|
||||
Point loc3 = points.get(2);
|
||||
Point loc4 = points.get(3);
|
||||
|
||||
swap(locBlank, locVal);
|
||||
swap(locVal, loc3);
|
||||
swap(loc3, loc1);
|
||||
swap(loc1, loc2);
|
||||
swap(loc2, locVal);
|
||||
swap(locVal, loc3);
|
||||
swap(loc3, loc1);
|
||||
swap(loc1, loc2);
|
||||
swap(loc2, locVal);
|
||||
swap(locVal, locBlank);
|
||||
swap(locBlank, loc4);
|
||||
swap(loc4, loc3);
|
||||
swap(loc3, loc1);
|
||||
swap(loc1, loc2);
|
||||
swap(loc2, locVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar;
|
||||
import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStarMM;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -83,8 +84,72 @@ public class PuzzleSolverTest
|
||||
new PuzzleState(new int[]{1, 5, 2, 3, 4, -1, 0, 7, 14, 8, 11, 6, 13, 9, 23, 10, 12, 15, 19, 17, 20, 21, 16, 22, 18}),
|
||||
};
|
||||
|
||||
private static final PuzzleState[] START_STATES_MM =
|
||||
{
|
||||
new PuzzleState(new int[]{0, 5, 1, 3, 4, 15, 2, 8, 10, 9, 22, 16, 11, 6, 14, 7, 21, 23, 12, 18, 20, -1, 17, 13, 19}),
|
||||
new PuzzleState(new int[]{0, 12, 8, 13, 4, 3, 16, 2, 1, 9, 21, 5, 6, 10, 14, 7, 17, 20, 18, -1, 15, 11, 22, 23, 19}),
|
||||
new PuzzleState(new int[]{1, 3, 7, 9, 8, 13, 17, 2, 4, 6, 15, 5, 22, 12, 14, 11, 0, 10, 21, -1, 20, 18, 16, 23, 19}),
|
||||
new PuzzleState(new int[]{5, 2, 16, 14, 4, 3, 0, 8, 9, 11, 15, 6, 17, 19, 7, 1, 10, -1, 23, 18, 20, 12, 21, 13, 22}),
|
||||
new PuzzleState(new int[]{0, 6, 1, 4, 13, 10, 2, 16, 7, 3, 20, -1, 8, 14, 9, 21, 5, 18, 11, 19, 17, 15, 12, 22, 23}),
|
||||
new PuzzleState(new int[]{5, 0, 1, 4, 8, 10, 6, 7, 12, 3, 17, 16, 21, 2, 9, 18, 20, 13, 14, 19, 11, -1, 23, 15, 22}),
|
||||
new PuzzleState(new int[]{1, 9, 2, 13, 17, 5, 7, 8, 3, 22, 6, -1, 16, 12, 4, 15, 18, 0, 23, 14, 10, 21, 11, 20, 19}),
|
||||
new PuzzleState(new int[]{1, 2, 11, 13, 4, 21, 7, 3, 6, 9, 0, 8, 10, 19, 14, 20, 12, 16, 23, -1, 5, 17, 15, 22, 18}),
|
||||
new PuzzleState(new int[]{2, 0, 1, 4, 13, 6, 7, 3, 8, 9, 22, 15, 10, 14, 18, 5, 12, -1, 17, 21, 20, 11, 23, 16, 19}),
|
||||
new PuzzleState(new int[]{0, 1, 2, 8, 3, 6, 12, 22, 9, 7, 11, 21, 13, 4, 14, 5, 10, -1, 18, 19, 20, 15, 16, 23, 17}),
|
||||
new PuzzleState(new int[]{1, 2, 3, 4, 8, 0, 6, 15, 14, 18, 16, 17, 20, -1, 9, 10, 12, 22, 11, 13, 21, 7, 5, 19, 23}),
|
||||
new PuzzleState(new int[]{0, 5, 2, 4, 9, 7, 15, 20, 12, 13, 6, -1, 22, 1, 8, 10, 11, 23, 14, 3, 21, 16, 17, 19, 18}),
|
||||
new PuzzleState(new int[]{0, 1, 9, 6, 13, 5, 18, -1, 4, 2, 15, 12, 3, 17, 7, 16, 10, 8, 23, 14, 20, 21, 19, 11, 22}),
|
||||
new PuzzleState(new int[]{11, 5, 12, 3, 4, 15, 8, 0, 7, 1, 6, -1, 19, 2, 9, 16, 10, 13, 17, 23, 20, 21, 22, 14, 18}),
|
||||
new PuzzleState(new int[]{10, 0, 1, 3, 4, 18, 5, 6, 12, 9, 7, 11, 8, -1, 22, 15, 23, 14, 19, 13, 20, 2, 17, 16, 21}),
|
||||
new PuzzleState(new int[]{19, -1, 6, 2, 4, 0, 21, 10, 3, 9, 1, 15, 17, 8, 14, 11, 13, 22, 7, 18, 16, 12, 5, 23, 20}),
|
||||
new PuzzleState(new int[]{11, 6, 3, 4, 9, 1, 10, 16, 2, 7, 5, 0, 13, -1, 12, 21, 8, 18, 17, 14, 15, 20, 22, 23, 19}),
|
||||
new PuzzleState(new int[]{0, 1, 5, 3, 4, -1, 6, 2, 15, 10, 7, 8, 23, 16, 13, 22, 11, 9, 12, 14, 20, 21, 18, 17, 19}),
|
||||
new PuzzleState(new int[]{10, 0, 1, -1, 2, 6, 5, 4, 13, 9, 16, 17, 12, 8, 19, 20, 15, 7, 21, 11, 22, 18, 14, 23, 3}),
|
||||
new PuzzleState(new int[]{1, 0, 5, 3, 9, 20, 15, 7, 2, 14, 6, 4, 12, -1, 8, 13, 18, 10, 23, 11, 21, 16, 17, 19, 22}),
|
||||
new PuzzleState(new int[]{0, 7, 6, 3, 4, 15, 1, 2, 8, 18, 11, 5, 13, -1, 22, 17, 16, 23, 14, 9, 20, 10, 12, 19, 21}),
|
||||
new PuzzleState(new int[]{5, 7, 0, 2, 9, 10, 1, 11, 3, 4, 16, 22, 8, 14, 17, 15, 20, 12, 13, 6, 21, 23, 19, -1, 18}),
|
||||
new PuzzleState(new int[]{3, 0, 1, 5, 4, 11, 6, 2, 16, 9, 15, 10, 7, 12, 13, 21, 19, -1, 22, 8, 20, 17, 14, 18, 23}),
|
||||
new PuzzleState(new int[]{6, 0, 3, 2, 4, 5, 1, 8, 13, 12, 15, 14, 10, 7, 9, -1, 22, 11, 19, 23, 16, 20, 17, 21, 18}),
|
||||
new PuzzleState(new int[]{11, 5, 6, 8, 9, 0, 21, 16, 4, 3, 17, 18, 2, 7, 1, 15, 10, -1, 22, 14, 20, 19, 13, 12, 23}),
|
||||
new PuzzleState(new int[]{2, 18, 3, 11, 4, -1, 5, 6, 12, 1, 10, 20, 0, 7, 9, 21, 15, 14, 23, 19, 16, 22, 13, 8, 17}),
|
||||
new PuzzleState(new int[]{0, 6, 8, 3, 1, 5, 2, 12, 9, 13, 16, 14, 19, 7, 18, 10, 11, -1, 4, 15, 20, 17, 23, 21, 22}),
|
||||
new PuzzleState(new int[]{1, 16, 10, 4, 3, 0, 15, 2, 9, -1, 8, 5, 23, 12, 6, 21, 18, 14, 13, 11, 20, 22, 7, 19, 17}),
|
||||
new PuzzleState(new int[]{1, 7, 6, 3, 4, 0, 2, 14, 5, 22, 18, 21, 16, 9, 13, 10, 20, -1, 8, 17, 15, 23, 11, 19, 12}),
|
||||
new PuzzleState(new int[]{5, 0, 1, 7, 9, 11, 8, 4, 2, 14, 15, 17, 18, -1, 3, 20, 10, 12, 22, 19, 16, 6, 13, 21, 23}),
|
||||
new PuzzleState(new int[]{5, 0, 6, 14, 7, 13, 15, 1, 3, 10, 20, 9, 17, 4, 2, 11, 12, 8, 19, -1, 21, 16, 22, 18, 23}),
|
||||
new PuzzleState(new int[]{12, 7, 8, 4, 9, 6, 11, 15, 2, 1, 5, -1, 13, 16, 3, 17, 0, 10, 18, 14, 20, 22, 21, 19, 23}),
|
||||
new PuzzleState(new int[]{15, 1, 2, 3, 14, -1, 20, 9, 4, 19, 0, 6, 7, 16, 13, 10, 5, 12, 17, 18, 22, 11, 21, 23, 8}),
|
||||
new PuzzleState(new int[]{0, 1, 17, -1, 14, 6, 4, 2, 3, 16, 10, 18, 13, 19, 9, 7, 5, 8, 21, 22, 11, 20, 15, 12, 23}),
|
||||
new PuzzleState(new int[]{5, 11, 9, 0, 3, 8, 14, -1, 6, 4, 1, 13, 7, 2, 19, 10, 21, 18, 23, 17, 15, 20, 12, 16, 22}),
|
||||
new PuzzleState(new int[]{2, 0, 14, -1, 4, 18, 1, 10, 12, 13, 5, 9, 11, 22, 7, 15, 8, 17, 19, 3, 20, 21, 6, 16, 23}),
|
||||
new PuzzleState(new int[]{0, 1, 13, 9, 2, 6, 8, 22, 3, 4, 12, 16, 10, 7, 19, -1, 5, 11, 14, 17, 15, 20, 21, 18, 23}),
|
||||
new PuzzleState(new int[]{0, 13, 17, 8, 3, 5, 1, 12, 14, 4, 10, -1, 6, 7, 9, 15, 23, 2, 16, 19, 20, 11, 21, 22, 18}),
|
||||
new PuzzleState(new int[]{5, 10, 7, 2, 9, 15, 0, -1, 1, 3, 18, 4, 17, 12, 14, 21, 11, 6, 8, 23, 20, 16, 22, 19, 13}),
|
||||
new PuzzleState(new int[]{0, 3, 1, 2, 4, 10, 5, 7, 8, 9, 11, 6, 21, 13, 12, 20, 17, -1, 14, 19, 22, 18, 15, 16, 23}),
|
||||
new PuzzleState(new int[]{0, 2, 7, 11, 13, 3, 14, 1, 4, 9, 5, -1, 12, 8, 18, 20, 10, 15, 22, 23, 17, 16, 6, 21, 19}),
|
||||
new PuzzleState(new int[]{0, 16, 3, 22, 7, 11, 6, -1, 9, 4, 2, 1, 13, 12, 18, 5, 10, 8, 19, 14, 15, 20, 17, 23, 21}),
|
||||
new PuzzleState(new int[]{0, 13, 5, 12, 3, 2, 10, 4, 6, 8, 1, 21, 19, 14, 9, 17, 23, 22, 16, 11, 15, 7, 20, -1, 18}),
|
||||
new PuzzleState(new int[]{14, 5, 6, 12, 4, 10, 20, 1, 0, 23, 2, 16, 13, 19, 3, 15, 22, -1, 9, 8, 11, 7, 18, 17, 21}),
|
||||
new PuzzleState(new int[]{0, 1, 2, 4, 7, 5, 11, -1, 18, 8, 16, 10, 12, 13, 3, 17, 6, 21, 23, 9, 15, 20, 22, 14, 19}),
|
||||
new PuzzleState(new int[]{1, 6, 7, 3, 4, 5, 17, 0, 22, 12, 10, 15, 8, -1, 14, 11, 13, 16, 18, 19, 20, 2, 21, 9, 23}),
|
||||
};
|
||||
|
||||
private static final int[] FINISHED_STATE = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -1};
|
||||
|
||||
@Test
|
||||
public void testSolverMM()
|
||||
{
|
||||
for (PuzzleState state : START_STATES_MM)
|
||||
{
|
||||
PuzzleSolver solver = new PuzzleSolver(new IDAStarMM(new ManhattanDistance()), state);
|
||||
solver.run();
|
||||
|
||||
assertTrue(solver.hasSolution());
|
||||
assertFalse(solver.hasFailed());
|
||||
assertTrue(solver.getStep(solver.getStepCount() - 1).hasPieces(FINISHED_STATE));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSolver()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user