use of net.runelite.client.plugins.puzzlesolver.solver.PuzzleState in project runelite by runelite.
the class PuzzleSolverOverlay method solve.
private void solve(int[] items) {
if (solverFuture != null) {
solverFuture.cancel(true);
}
PuzzleState puzzleState = new PuzzleState(items);
solver = new PuzzleSolver(new IDAStar(new ManhattanDistance()), puzzleState);
solverFuture = executorService.submit(solver);
}
use of net.runelite.client.plugins.puzzlesolver.solver.PuzzleState in project runelite by runelite.
the class PuzzleSolverOverlay method render.
@Override
public Dimension render(Graphics2D graphics) {
if ((!config.displaySolution() && !config.displayRemainingMoves()) || client.getGameState() != GameState.LOGGED_IN) {
return null;
}
ItemContainer container = client.getItemContainer(InventoryID.PUZZLE_BOX);
if (container == null) {
return null;
}
Widget puzzleBox = client.getWidget(WidgetInfo.PUZZLE_BOX);
if (puzzleBox == null) {
return null;
}
net.runelite.api.Point puzzleBoxLocation = puzzleBox.getCanvasLocation();
String infoString = "Solving..";
int[] itemIds = getItemIds(container);
boolean shouldCache = false;
if (solver != null) {
if (solver.hasFailed()) {
infoString = "The puzzle could not be solved";
} else {
if (solver.hasSolution()) {
boolean foundPosition = false;
// Find the current state by looking at the current step and then the next 5 steps
for (int i = 0; i < 6; i++) {
int j = solver.getPosition() + i;
if (j == solver.getStepCount()) {
break;
}
PuzzleState currentState = solver.getStep(j);
// If this is false, player has moved the empty tile
if (currentState != null && currentState.hasPieces(itemIds)) {
foundPosition = true;
solver.setPosition(j);
if (i > 0) {
shouldCache = true;
}
break;
}
}
// see if we can find the current state in the 5 previous steps
if (!foundPosition) {
for (int i = 1; i < 6; i++) {
int j = solver.getPosition() - i;
if (j < 0) {
break;
}
PuzzleState currentState = solver.getStep(j);
if (currentState != null && currentState.hasPieces(itemIds)) {
foundPosition = true;
shouldCache = true;
solver.setPosition(j);
break;
}
}
}
if (foundPosition) {
int stepsLeft = solver.getStepCount() - solver.getPosition() - 1;
if (stepsLeft == 0) {
infoString = "Solved!";
} else if (config.displayRemainingMoves()) {
infoString = "Moves left: " + stepsLeft;
} else {
infoString = null;
}
if (config.displaySolution()) {
if (config.drawDots()) {
graphics.setColor(Color.YELLOW);
// Display the next 4 steps
for (int i = 1; i < 5; i++) {
int j = solver.getPosition() + i;
if (j >= solver.getStepCount()) {
break;
}
PuzzleState futureMove = solver.getStep(j);
if (futureMove == null) {
break;
}
int blankX = futureMove.getEmptyPiece() % DIMENSION;
int blankY = futureMove.getEmptyPiece() / DIMENSION;
int markerSize = DOT_MARKER_SIZE - i * 3;
int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE + PUZZLE_TILE_SIZE / 2 - markerSize / 2;
int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE + PUZZLE_TILE_SIZE / 2 - markerSize / 2;
graphics.fillOval(x, y, markerSize, markerSize);
}
} else {
// Find the current blank tile position
PuzzleState currentMove = solver.getStep(solver.getPosition());
int lastBlankX = currentMove.getEmptyPiece() % DIMENSION;
int lastBlankY = currentMove.getEmptyPiece() / DIMENSION;
// Display the next 3 steps
for (int i = 1; i < 4; i++) {
int j = solver.getPosition() + i;
if (j >= solver.getStepCount()) {
break;
}
PuzzleState futureMove = solver.getStep(j);
if (futureMove == null) {
break;
}
int blankX = futureMove.getEmptyPiece() % DIMENSION;
int blankY = futureMove.getEmptyPiece() / DIMENSION;
int xDelta = blankX - lastBlankX;
int yDelta = blankY - lastBlankY;
BufferedImage arrow;
if (xDelta > 0) {
arrow = getRightArrow();
} else if (xDelta < 0) {
arrow = getLeftArrow();
} else if (yDelta > 0) {
arrow = getDownArrow();
} else {
arrow = getUpArrow();
}
int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE + PUZZLE_TILE_SIZE / 2 - arrow.getWidth() / 2;
int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE + PUZZLE_TILE_SIZE / 2 - arrow.getHeight() / 2;
OverlayUtil.renderImageLocation(graphics, new net.runelite.api.Point(x, y), arrow);
lastBlankX = blankX;
lastBlankY = blankY;
}
}
}
}
}
}
}
// Draw info box
if (infoString != null) {
int x = puzzleBoxLocation.getX() + puzzleBox.getWidth() / 2 - INFO_BOX_WIDTH / 2;
int y = puzzleBoxLocation.getY() - INFO_BOX_OFFSET_Y;
FontMetrics fm = graphics.getFontMetrics();
int height = INFO_BOX_TOP_BORDER + fm.getHeight() + INFO_BOX_BOTTOM_BORDER;
BackgroundComponent backgroundComponent = new BackgroundComponent();
backgroundComponent.setRectangle(new Rectangle(x, y, INFO_BOX_WIDTH, height));
backgroundComponent.render(graphics);
int textOffsetX = (INFO_BOX_WIDTH - fm.stringWidth(infoString)) / 2;
int textOffsetY = fm.getHeight();
TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(x + textOffsetX, y + textOffsetY));
textComponent.setText(infoString);
textComponent.render(graphics);
}
// Solve the puzzle if we don't have an up to date solution
if (solver == null || cachedItems == null || (!shouldCache && !Arrays.equals(cachedItems, itemIds))) {
solve(itemIds);
shouldCache = true;
}
if (shouldCache) {
cacheItems(itemIds);
}
return null;
}
use of net.runelite.client.plugins.puzzlesolver.solver.PuzzleState in project runelite by runelite.
the class IDAStar method computePath.
@Override
public List<PuzzleState> computePath(PuzzleState root) {
PuzzleState goalNode = path(root);
if (goalNode == null) {
return null;
}
List<PuzzleState> path = new ArrayList<>();
PuzzleState parent = goalNode;
while (parent != null) {
path.add(0, parent);
parent = parent.getParent();
}
return path;
}
use of net.runelite.client.plugins.puzzlesolver.solver.PuzzleState in project runelite by runelite.
the class IDAStar method path.
private PuzzleState path(PuzzleState root) {
int bound = root.getHeuristicValue(getHeuristic());
while (true) {
PuzzleState t = search(root, 0, bound);
if (t != null) {
return t;
}
bound += 1;
}
}
use of net.runelite.client.plugins.puzzlesolver.solver.PuzzleState in project runelite by runelite.
the class ManhattanDistance method computeValue.
@Override
public int computeValue(PuzzleState state) {
int value = 0;
PuzzleState parent = state.getParent();
if (parent == null) {
for (int x = 0; x < DIMENSION; x++) {
for (int y = 0; y < DIMENSION; y++) {
int piece = state.getPiece(x, y);
if (piece == -1) {
continue;
}
int goalX = piece % DIMENSION;
int goalY = piece / DIMENSION;
value += Math.abs(x - goalX) + Math.abs(y - goalY);
}
}
} else {
/*
If the Manhattan distance for the parent has already been
calculated, we can take advantage of that and just
add/subtract from their heuristic value.
Doing this decreases the execution time of the heuristic by about 25%.
*/
value = parent.getHeuristicValue(this);
int x = parent.getEmptyPiece() % DIMENSION;
int y = parent.getEmptyPiece() / DIMENSION;
int x2 = state.getEmptyPiece() % DIMENSION;
int y2 = state.getEmptyPiece() / DIMENSION;
int piece = state.getPiece(x, y);
if (x2 > x) {
int targetX = piece % DIMENSION;
// right
if (targetX > x)
value++;
else
value--;
} else if (x2 < x) {
int targetX = piece % DIMENSION;
// left
if (targetX < x)
value++;
else
value--;
} else if (y2 > y) {
int targetY = piece / DIMENSION;
// down
if (targetY > y)
value++;
else
value--;
} else {
int targetY = piece / DIMENSION;
// up
if (targetY < y)
value++;
else
value--;
}
}
return value;
}
Aggregations