This commit is contained in:
vanni
2019-05-02 06:04:49 -04:00
committed by Kyleeld
parent cfc3a09179
commit 921ec3e0db
6 changed files with 584 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
package net.runelite.client.plugins.runedoku;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import java.awt.*;
@ConfigGroup("runedoku")
public interface RunedokuConfig extends Config {
@ConfigItem(
position = 0,
keyName = "mindRuneColor",
name = "Mind Rune Color",
description = "Color used to highlight Mind runes."
)
default Color mindRuneColor() { return Color.PINK; }
@ConfigItem(
position = 1,
keyName = "fireRuneColor",
name = "Fire Rune Color",
description = "Color used to highlight Fire runes."
)
default Color fireRuneColor() { return Color.RED; }
@ConfigItem(
position = 2,
keyName = "bodyRuneColor",
name = "Body Rune Color",
description = "Color used to highlight Body runes."
)
default Color bodyRuneColor() { return Color.MAGENTA; }
@ConfigItem(
position = 3,
keyName = "airRuneColor",
name = "Air Rune Color",
description = "Color used to highlight Air runes."
)
default Color airRuneColor() { return Color.WHITE; }
@ConfigItem(
position = 4,
keyName = "deathRuneColor",
name = "Death Rune Color",
description = "Color used to highlight Death runes."
)
default Color deathRuneColor() { return Color.BLACK; }
@ConfigItem(
position = 5,
keyName = "waterRuneColor",
name = "Water Rune Color",
description = "Color used to highlight Water runes."
)
default Color waterRuneColor() { return Color.BLUE; }
@ConfigItem(
position = 6,
keyName = "chaosRuneColor",
name = "Chaos Rune Color",
description = "Color used to highlight Chaos runes."
)
default Color chaosRuneColor() { return Color.YELLOW; }
@ConfigItem(
position = 7,
keyName = "earthRuneColor",
name = "Earth Rune Color",
description = "Color used to highlight Earth runes."
)
default Color earthRuneColor() { return Color.GREEN; }
@ConfigItem(
position = 8,
keyName = "lawRuneColor",
name = "Law Rune Color",
description = "Color used to highlight Law runes."
)
default Color lawRuneColor() { return Color.CYAN; }
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2019, gazivodag <https://github.com/gazivodag>
* 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.runedoku;
import net.runelite.api.Client;
import net.runelite.api.widgets.Widget;
import net.runelite.client.ui.overlay.*;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import javax.inject.Inject;
import java.awt.*;
import java.util.ArrayList;
import static java.awt.Color.RED;
/**
* @author gazivodag
*/
class RunedokuOverlay extends Overlay {
private final RunedokuPlugin plugin;
private final Client client;
private final RunedokuUtil util;
@Inject
private RunedokuOverlay(final RunedokuPlugin plugin, final Client client, final RunedokuUtil util) {
super(plugin);
this.plugin = plugin;
this.client = client;
this.util = util;
setPosition(OverlayPosition.DETACHED);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
setPriority(OverlayPriority.MED);
}
@Override
public Dimension render(Graphics2D graphics) {
final Widget sudokuScreen = client.getWidget(288,131);
if (sudokuScreen != null) {
if (!sudokuScreen.isHidden()) {
Sudoku sudoku = new Sudoku(util.createTable(client));
boolean solved = sudoku.solve();
renderReferenceRunes(graphics, solved);
renderSolvedPuzzle(graphics, sudoku, solved);
}
}
return null;
}
/**
* highlights the runes on the left handside so you know which runes to place on the board
* @param graphics
* @param solved
*/
private void renderReferenceRunes(Graphics2D graphics, boolean solved) {
//reference runes on the left handside
for (int i = 121 ; i < 130 ; i++) {
Widget widget = client.getWidget(288, i);
if (solved) {
if (!util.makeSimple(util.createTable(client)).contains(0)) {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), Color.GREEN);
} else {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), util.referenceColors(i));
}
} else {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), RED);
}
}
}
/**
* goes through each 9x9 cell and tells you which piece to place in there
* @param graphics
* @param sudoku
* @param solved
*/
private void renderSolvedPuzzle(Graphics2D graphics, Sudoku sudoku, boolean solved) {
ArrayList<Integer> simpleArr = util.makeSimple(sudoku.getBoard());
//highlight each cell to tell you which piece to place
int iteration = 0;
for (int i = 10 ; i < 91 ; i++) {
Widget squareToHighlight = client.getWidget(288, i);
if (solved) {
if (!util.makeSimple(util.createTable(client)).contains(0)) {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), Color.GREEN);
} else {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), util.sudokuPieceToColor(simpleArr.get(iteration)));
}
iteration++;
} else {
OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), RED);
}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2019, gazivodag <https://github.com/gazivodag>
* 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.runedoku;
public enum RunedokuPiece {
NPC_PLACED_MIND_RUNE(6436, 1), //1
NPC_PLACED_FIRE_RUNE(6428, 2), //2
NPC_PLACED_BODY_RUNE(6438, 3), //3
NPC_PLACED_AIR_RUNE(6422, 4), //4
NPC_PLACED_DEATH_RUNE(6432, 5), //5
NPC_PLACED_WATER_RUNE(6424, 6), //6
NPC_PLACED_CHAOS_RUNE(6430, 7), //7
NPC_PLACED_EARTH_RUNE(6426, 8), //8
NPC_PLACED_LAW_RUNE(6434, 9), //9
PLAYER_PLACED_MIND_RUNE(558, 1), //1
PLAYER_PLACED_FIRE_RUNE(554, 2), //2
PLAYER_PLACED_BODY_RUNE(559, 3), //3
PLAYER_PLACED_AIR_RUNE(556, 4), //4
PLAYER_PLACED_DEATH_RUNE(560, 5), //5
PLAYER_PLACED_WATER_RUNE(555, 6), //6
PLAYER_PLACED_CHAOS_RUNE(562, 7), //7
PLAYER_PLACED_EARTH_RUNE(557, 8), //8
PLAYER_PLACED_LAW_RUNE(563, 9), //9
;
private final int pieceID;
private final int pieceForSudoku;
RunedokuPiece (int pieceID, int pieceForSudoku) {
this.pieceID = pieceID;
this.pieceForSudoku = pieceForSudoku;
}
int getId () {
return pieceID;
}
int getPieceForSudoku() {
return pieceForSudoku;
}
static RunedokuPiece getById(int pieceID) {
for (RunedokuPiece e : RunedokuPiece.values()) {
if (e.getId() == pieceID) {
return e;
}
}
return null;
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2019, gazivodag <https://github.com/gazivodag>
* 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.runedoku;
import com.google.inject.Provides;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.overlay.OverlayManager;
import javax.inject.Inject;
import javax.inject.Singleton;
@PluginDescriptor(
name = "Runedoku Solver",
description = "Show solutions for current Runedoku puzzle.",
tags = {"overlay", "runedoku", "sudoku", "puzzle", "solving"},
type = PluginType.UTILITY
)
@Slf4j
@Singleton
public class RunedokuPlugin extends Plugin {
@Inject
private Client client;
@Inject
RunedokuUtil util;
@Inject
private OverlayManager overlayManager;
@Inject
private RunedokuOverlay runedokuOverlay;
@Inject
private RunedokuConfig config;
@Provides
RunedokuConfig provideConfig(ConfigManager configManager) {
return configManager.getConfig(RunedokuConfig.class);
}
@Override
protected void startUp() throws Exception {
overlayManager.add(runedokuOverlay);
}
@Override
protected void shutDown() throws Exception {
overlayManager.remove(runedokuOverlay);
}
}

View File

@@ -0,0 +1,126 @@
package net.runelite.client.plugins.runedoku;
import net.runelite.api.Client;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetItem;
import javax.inject.Inject;
import java.awt.*;
import java.util.ArrayList;
public class RunedokuUtil {
private final RunedokuConfig config;
@Inject
RunedokuUtil(final RunedokuConfig config) {
this.config = config;
}
protected Color sudokuPieceToColor(int i) {
switch (i) {
case 1:
return config.mindRuneColor();
case 2:
return config.fireRuneColor();
case 3:
return config.bodyRuneColor();
case 4:
return config.airRuneColor();
case 5:
return config.deathRuneColor();
case 6:
return config.waterRuneColor();
case 7:
return config.chaosRuneColor();
case 8:
return config.earthRuneColor();
case 9:
return config.lawRuneColor();
default:
return Color.RED;
}
}
protected Color referenceColors(int i) {
switch (i) {
case 121: //earth
return config.earthRuneColor();
case 122: //water
return config.waterRuneColor();
case 123: //air
return config.airRuneColor();
case 124: //mind
return config.mindRuneColor();
case 125: //fire
return config.fireRuneColor();
case 126: //body
return config.bodyRuneColor();
case 127: //death
return config.deathRuneColor();
case 128: //chaos
return config.chaosRuneColor();
case 129: //law
return config.lawRuneColor();
default:
return Color.RED;
}
}
/**
* Make the 2d array into an arraylist
* @param board
* @return
*/
protected ArrayList<Integer> makeSimple(int[][] board) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0 ; i < 9 ; i++) {
for (int ii = 0 ; ii < 9 ; ii++) {
list.add(board[i][ii]);
}
}
return list;
}
/**
* utility method
* @param rect
* @return
*/
protected Polygon RectangleToPolygon(Rectangle rect) {
int[] xpoints = {rect.x, rect.x + rect.width, rect.x + rect.width, rect.x};
int[] ypoints = {rect.y, rect.y, rect.y + rect.height, rect.y + rect.height};
return new Polygon(xpoints, ypoints, 4);
}
/**
* Pulls data from what's on the Runedoku interface and creates a 2dimensional array for it
* @author gazivodag
* @param client
* @return sudoku table that the client currently sees in a 2d array
*/
protected int[][] createTable(Client client) {
int[][] myArr = new int[9][9];
Widget sudokuScreen = client.getWidget(288,131);
for (int i = 0 ; i < 9 ; i++) {
for (int ii = 0 ; ii < 9 ; ii++) {
WidgetItem item;
int myIndex;
if (i > 0) {
myIndex = ((i * 10) + ii) - i;
} else {
myIndex = ii;
}
if (myIndex == 81) break;
item = sudokuScreen.getWidgetItem(myIndex);
if (item != null) {
myArr[i][ii] = RunedokuPiece.getById(item.getId()).getPieceForSudoku();
} else {
myArr[i][ii] = 0;
}
}
}
return myArr;
}
}

View File

@@ -0,0 +1,92 @@
package net.runelite.client.plugins.runedoku;
/**
* Credits to whoever wrote this sudoku class.
* @author ?
*/
public class Sudoku {
private int[][] board;
public static final int EMPTY = 0;
public static final int SIZE = 9;
Sudoku(int[][] board) {
this.board = new int[SIZE][SIZE];
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
this.board[i][j] = board[i][j];
}
}
}
private boolean isInRow(int row, int number) {
for (int i = 0; i < SIZE; i++)
if (board[row][i] == number)
return true;
return false;
}
private boolean isInCol(int col, int number) {
for (int i = 0; i < SIZE; i++)
if (board[i][col] == number)
return true;
return false;
}
private boolean isInBox(int row, int col, int number) {
int r = row - row % 3;
int c = col - col % 3;
for (int i = r; i < r + 3; i++)
for (int j = c; j < c + 3; j++)
if (board[i][j] == number)
return true;
return false;
}
private boolean isOk(int row, int col, int number) {
return !isInRow(row, number) && !isInCol(col, number) && !isInBox(row, col, number);
}
public boolean solve() {
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if (board[row][col] == EMPTY) {
for (int number = 1; number <= SIZE; number++) {
if (isOk(row, col, number)) {
board[row][col] = number;
if (solve()) {
return true;
} else {
board[row][col] = EMPTY;
}
}
}
return false;
}
}
}
return true;
}
public void display() {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
System.out.print(" " + board[i][j]);
}
System.out.println();
}
System.out.println();
}
public int[][] getBoard() {
return board;
}
}