Search in sources :

Example 1 with PuzzleState

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);
}
Also used : IDAStar(net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar) PuzzleState(net.runelite.client.plugins.puzzlesolver.solver.PuzzleState) PuzzleSolver(net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver) ManhattanDistance(net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance)

Example 2 with PuzzleState

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;
}
Also used : ItemContainer(net.runelite.api.ItemContainer) TextComponent(net.runelite.client.ui.overlay.components.TextComponent) PuzzleState(net.runelite.client.plugins.puzzlesolver.solver.PuzzleState) Widget(net.runelite.api.widgets.Widget) Rectangle(java.awt.Rectangle) Point(java.awt.Point) Point(java.awt.Point) BufferedImage(java.awt.image.BufferedImage) BackgroundComponent(net.runelite.client.ui.overlay.components.BackgroundComponent) FontMetrics(java.awt.FontMetrics)

Example 3 with PuzzleState

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;
}
Also used : PuzzleState(net.runelite.client.plugins.puzzlesolver.solver.PuzzleState) ArrayList(java.util.ArrayList)

Example 4 with PuzzleState

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;
    }
}
Also used : PuzzleState(net.runelite.client.plugins.puzzlesolver.solver.PuzzleState)

Example 5 with PuzzleState

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;
}
Also used : PuzzleState(net.runelite.client.plugins.puzzlesolver.solver.PuzzleState)

Aggregations

PuzzleState (net.runelite.client.plugins.puzzlesolver.solver.PuzzleState)7 PuzzleSolver (net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver)2 ManhattanDistance (net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance)2 IDAStar (net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar)2 FontMetrics (java.awt.FontMetrics)1 Point (java.awt.Point)1 Rectangle (java.awt.Rectangle)1 BufferedImage (java.awt.image.BufferedImage)1 ArrayList (java.util.ArrayList)1 ItemContainer (net.runelite.api.ItemContainer)1 Widget (net.runelite.api.widgets.Widget)1 BackgroundComponent (net.runelite.client.ui.overlay.components.BackgroundComponent)1 TextComponent (net.runelite.client.ui.overlay.components.TextComponent)1 Test (org.junit.Test)1