Add puzzle solver for monkey madness 1 puzzle box (#6545)

* Add puzzle solver for monkey madness 1 puzzle box
This commit is contained in:
steffenhauge
2019-01-04 21:44:00 +01:00
committed by Lotto
parent 1af2dac241
commit 72cce77784
6 changed files with 940 additions and 25 deletions

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}