(Java, Bukkit) Using extended class methods don't work (Noob oop) - java

I have one class named 'Regions', which make region and check if coordinates are in it. Then I have other class 'ArrowTower' which extends 'Region'. Class 'ArrowTower' creates towers. All day I was experimenting with no results. What I want to do is assign first and second location to class 'Regions' then make region and check if coordinates belongs to it. I also have events - 'BlockTouch' class which creates 'ArrowTower' object.. When I try to tower.insideRegion(e.getClickedBlock()); it gives me my location and then zeros, because it didin't set values in public void buildArrowTower, but values are right here. So I just don't understand why this isn't working :/
My Events class:
import eu.anavicius.TomTom1997.TomTowerDefence.Towers.ArrowTower;
public class BlockTouch implements Listener {
#EventHandler
public void onPlayerInteract(PlayerInteractEvent e) {
ArrowTower tower = new ArrowTower();
if (e.getAction() == Action.RIGHT_CLICK_BLOCK ) {
if (e.getItem().getType() == Material.ARROW) {
tower.buildArrowTower(e.getClickedBlock(),e.getPlayer());
} else if (e.getItem().getType() == Material.BONE) {
Bukkit.broadcastMessage("Bone");
tower.insideRegion(e.getClickedBlock());
}
}
}
}
My Region.class:
public class Regions {
private int xl,yl,zl,xh,yh,zh;
public void setLRegion (int x, int y, int z) {
xl = x;
yl = y;
zl = z;
//Bukkit.broadcastMessage("SetLMethod" + " \t " + "|" + xl + "|"+ xh + "||" + "|" + yl + "|" + yh + "||" + "|" +zl + "|" + zh + "||");
}
public void setHRegion (int x, int y, int z) {
xh = x;
yh = y;
zh = z;
//Bukkit.broadcastMessage("SetHMethod" + " \t " + "|" + xl + "|"+ xh + "||" + "|" + yl + "|" + yh + "||" + "|" +zl + "|" + zh + "||");
}
public void insideRegion (Block l) {
int x,y,z;
x = l.getX();
y = l.getY();
z =l.getZ();
Bukkit.broadcastMessage("InsideMethod" + " \\t " + x + "|" + xl + "|"+ xh + "||" +y + "|" + yl + "|" + yh + "||" + z + "|" +zl + "|" + zh + "||");
if (x >= xl && x <= xh ) {
Bukkit.broadcastMessage("Region check 1");
if (z >= zl && z <= zh) {
Bukkit.broadcastMessage("Region check 2");
if (y >= yl && y >= yh) {
Bukkit.broadcastMessage("Regione");
}
}
}
}
}
My ArrowTower.class:
public class ArrowTower extends Regions {
public ArrowTower () {
}
public void buildArrowTower (Block b,Player p) {
if (b.getType().equals(Material.EMERALD_BLOCK)) {
Location loc = b.getLocation();
for (int y = 0; y < 4;y++) {
int layloc = 0;
int by = loc.getBlock().getY()+1 + y;
for (int x = 0;x <3;x++) {
int bx = loc.getBlock().getX()-1 + x;
for (int z = 0;z < 3;z++) { // Pagalvot dar del delay, nes su kintamaisiais pirma blogai buvau
int bz = loc.getBlock().getZ()-1 + z; // sugalvojas, atsispausdina tuscios vietos
Location block = new Location(b.getWorld(),bx,by,bz); // pass loop values to method
if (y == 0 && layloc == 0) {
Bukkit.broadcastMessage("SetR L");
setLRegion(bx,by,bz);
} else if (y == 3 && layloc == 8) {
Bukkit.broadcastMessage("SetR H");
setHRegion(bx,by,bz);
}
block.getBlock().setType(Material.matchMaterial(towerl1(y,layloc)));
layloc++;
}
}
}
}
}
public String towerl1(int h, int layloc) {
String[] layer1 = { // - l
"LOG","AIR","LOG",
"AIR","AIR","AIR",
"LOG","AIR","LOG"};
String[] layer2 = { // - i
"COBBLE_WALL","COBBLESTONE","COBBLE_WALL",
"COBBLESTONE","AIR","COBBLESTONE",
"COBBLE_WALL","COBBLESTONE","COBBLE_WALL"};
String[] layer3 = { // - t
"COBBLE_WALL","AIR","COBBLE_WALL",
"COBBLE_WALL","MOSSY_COBBLESTONE","COBBLE_WALL",
"COBBLE_WALL","AIR","COBBLE_WALL"};
String[] layer4 = {
"AIR","AIR","AIR",
"AIR","JACK_O_LANTERN","AIR",
"AIR","AIR","AIR"};
if (h == 0) {
return layer1[layloc];
} else if (h == 1) {
return layer2[layloc];
} else if (h == 2) {
return layer3[layloc];
} else if (h == 3) {
return layer4[layloc];
} else {
return null;
}
}
}

The problem is that you create a new ArrowTower object on each interact event. I assume you first right-click on a block while holding an arrow in your hand - that's when tower.buildArrowTower(e.getClickedBlock(),e.getPlayer()); is called.
Then you take a bone in your hand, and click again - but this time your event handler will create a completely new ArrowTower with it's first line (actually you don't even have a reference to the first one, since it was only declared in the function's scope):
ArrowTower tower = new ArrowTower();
Then you call:
tower.insideRegion(e.getClickedBlock());
but this tower was just created - actually it's xh, yh, etc. values weren't ever initialized.

Related

Minecraft Bukkit coding Type mismatch: cannot convert from element type Object to String

Here is the full code for it:
public void trackAll() {
int north = count(Direction.North) * 25;
int east = count(Direction.East) * 25;
int south = count(Direction.South) * 25;
int west = count(Direction.West) * 25;
if ((north == 0) && (east == 0) && (south == 0) && (west == 0)) {
this.player.sendMessage(ChatColor.RED + "Not a valid tracking compass.");
return;
}
for (Direction direction : Direction.values()) {
int length = count(direction) * 25;
if (length != 0) {
#SuppressWarnings("rawtypes")
Set players = new TreeSet();
for (Player player : Bukkit.getOnlinePlayers()) {
if (this.player.canSee(player)) if ((on(player, direction) & !player.equals(this.player))) {
players.add(player.getDisplayName());
}
}
FancyMessage message = new FancyMessage(direction + " (" + length + "): ").color(ChatColor.DARK_AQUA);
int i = 0;
for (String str : players) {
if (i == players.size() - 1)
message.then(str).color(ChatColor.GRAY).tooltip(ChatColor.GREEN + "Click here to track " + ChatColor.RESET + str + ChatColor.GREEN + ".").command("/track " + ChatColor.stripColor(str));
else {
message.then(str).color(ChatColor.GRAY).tooltip(ChatColor.GREEN + "Click here to track " + ChatColor.RESET + str + ChatColor.GREEN + ".").command("/track " + ChatColor.stripColor(str)).then(", ");
}
i++;
}
message.send(this.player);
}
}
}
And I also have another issue "Type mismatch: cannot convert from element type Object to Block"
public int count(Direction direction, boolean b) {
int length = 0;
#SuppressWarnings("rawtypes")
Set toDelete = new HashSet();
for (int i = 1; i < 10000; i++) {
Block next = this.middle.getRelative(BlockFace.valueOf(direction.toString().toUpperCase()), i);
if (next.getType() == Material.COBBLESTONE) {
length++;
toDelete.add(next); } else {
if (next.getType() == Material.STONE) {
length++;
toDelete.add(next);
toDelete.add(this.middle);
break;
}
length = 0;
toDelete.clear();
break;
}
}
if (b) {
for (Block block : toDelete) {
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getTypeId());
block.setType(Material.AIR);
}
}
return length;
}
I currently don't have someone that can look over the code I personally do not see the issue but I've been working on it for hours so yeah ;/ Thanks. This code is to do with a Minecraft plugin it's tracking a players location and sending the information to the player that executed the command.
Use
Set<String> players = new TreeSet<>();
and
Set<Block> toDelete = new HashSet<>();

Simple instance variable issue

I'm working on a small personal project involving elliptic curves, and I'm having a bit of difficulty with the curve's instance variables. The variables are printed correctly in the main method, but the print method always returns that each variable is equal to 0. Does anyone see a way to fix this? Please bear with me, I know that this is a fairly trivial problem.
public class ellipticcurve {
public int A, B, p;
public ellipticcurve(int A, int B, int p) {
A = this.A;
B = this.B;
p = this.p;
// E:= Y^2 = X^3 + AX + B
}
public static boolean isAllowed(int a, int b, int p) {
return ((4*(Math.pow(a, 3)) + 27*(Math.pow(b, 2)))%p != 0);
}
public static void printCurve(ellipticcurve E) {
System.out.println("E(F" + E.p + ") := Y^2 = X^3 + " + E.A + "X + " + E.B + ".");
}
public static void main(String[] args) {
ArgsProcessor ap = new ArgsProcessor(args);
int a = ap.nextInt("A-value:");
int b = ap.nextInt("B-value:");
int p = ap.nextInt("Prime number p for the field Fp over which the curve is defined:");
while (isAllowed(a, b, p) == false) {
System.out.println("The parameters you have entered do not satisfy the "
+ "congruence 4A^3 + 27B^2 != 0 modulo p.");
a = ap.nextInt("Choose a new A-value:");
b = ap.nextInt("Choose a new B-value:");
p = ap.nextInt("Choose a new prime number p for the field Fp over which the curve is defined:");
}
ellipticcurve curve = new ellipticcurve(a, b, p);
System.out.println(curve.A + " " + curve.B + " " + curve.p);
printCurve(curve);
System.out.println("The elliptic curve is given by E(F" + p
+ ") := Y^2 = X^3 + " + a + "X + " + b + ".");
}
In your constructor it should be in this way.
public ellipticcurve(int A, int B, int p) {
this.A = A;
this.B = B;
this.p = p;
// E:= Y^2 = X^3 + AX + B
}
instead of
public ellipticcurve(int A, int B, int p) {
A = this.A;
B = this.B;
p = this.p;
// E:= Y^2 = X^3 + AX + B
}
You are assigning the instance variable to the variable passed in the constructor so the instance variable will be initialized to their default value

Java - using logical OR in do while

I'm fairly new at this programming, so please do bear with me.
In teaching myself I'm attempting to write a Batteleships game; not OO at the moment, but rather procedural - little steps at a time.
I have a method to read the coordinates to fire at, these coordinates I want to then validate to make sure that, well, they're valid.
There is one method that checks that they are numbers and within the correct range, the other method is 'supposed' to check through what has already been entered.
The issue I'm finding is that I'm not breaking out of the do while loop to progress, the while bit is using logical OR on the two aforementioned methods. In writing these methods, they both do what they're supposed to do, well I'm not entirely sure about the method that checks whether a coordinate has already been fired at.
Some pointers would be really appreciated (on any aspect of it), thanks!
Code:
public static String inputCoords(List<String> coordsFired){
Scanner sc = new Scanner(System.in);
//Console c = System.console();
String coordsEntered;
do {
System.out.println("in do\\while");
System.out.println("Enter coordinates as 'x, y': ");
coordsEntered = sc.nextLine();
System.out.println("end of do\\while loop");
} while(!validateCoords(coordsEntered)
|| !coordsFiredAt(coordsEntered, coordsFired));
coordsFired.add(coordsEntered);
System.out.println("contents of List<String> coordsFired" + coordsFired);
return coordsEntered;
}
public static boolean validateCoords(String coordsEntered){
boolean results;
int x, y;
String strx = splitCoordsString(coordsEntered, 'x');
String stry = splitCoordsString(coordsEntered, 'y');
if (numericCheckCoordsFire(strx) && numericCheckCoordsFire(stry)) {
x = Integer.parseInt(strx);
y = Integer.parseInt(stry);
if (x > 25 || y > 25) {
results = false;
System.out.println("The dimensions of the board are 25 x 25, 'x,y' entered must be less than this. You entered '" + strx + "' for x and '" + stry + "' for y.");
} else {
results = true;
}
} else {
results = false;
System.out.println("Coords are supposed to be numbers... You entered '" + strx + "' for x and '" + stry + "' for y.");
}
System.out.println(results);
return results;
}
public static boolean coordsFiredAt(String coordsEntered, List<String> coordsFired) {
boolean results = false;
// go through each item in the list and compare against coordsEntered
for (String s : coordsFired) {
System.out.println("in for loop, printing iterated var" + s);
if (s.equals(coordsEntered)) {
// put these matched coordsFire into listHit
results = false;
} else {
System.out.println("already fired at " + coordsEntered);
results = true;
}
}
return results;
}
I propose you add OOP a little and create a class for Coords:
public class Coords {
private final int x;
private final int y;
public Coords(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
/**
* This method is used for Coords comparison
*/
#Override
public boolean equals(Object o) {
Coords coords = (Coords) o;
return y == coords.y && coords.x ==x;
}
/**
* This method is used to output coords.
*/
#Override
public String toString() {
return "(" + x + "," + y + ")";
}
}
So you code will look somethink like this:
public static Coords inputCoords(List<Coords> coordsFired) {
Scanner sc = new Scanner(System.in);
//Console c = System.console();
Coords coords;
do {
System.out.println("in do\\while");
System.out.println("Enter coordinates as 'x, y': ");
String coordsEntered = sc.nextLine();
coords = parseCoords(coordsEntered);
System.out.println("end of do\\while loop");
} while (coords == null || !areCoordsValid(coords) || !areCoordsNotFired(coords, coordsFired));
coordsFired.add(coords);
System.out.println("contents of List<String> coordsFired" + coordsFired);
return coords;
}
public static boolean areCoordsValid(Coords coords) {
boolean result = true;
if (coords.getX() > 25 || coords.getY() > 25) { // I think you also need to validate that it is possible values
result = false;
System.out.println("The dimensions of the board are 25 x 25, 'x,y' entered must be less than this. " +
"You entered '" + coords.getX() + "' for x and '" + coords.getY() + "' for y.");
}
return result;
}
public static boolean areCoordsNotFired(Coords coords, List<Coords> firedCoards) {
boolean result = true;
if (firedCoards.contains(coords)) {
result = false;
System.out.println("You already fired at " + coords.getX() + "," + coords.getY());
}
return result;
}
public static Coords parseCoords(String coordsEntered) {
Coords coords = null;
try {
String[] splittedCoords = coordsEntered.split(","); // Method splits values by comma. It should return an array of Strings with x value at the first element and y at the second one;
if (splittedCoords.length == 2) {
String x = splittedCoords[0].trim(); // Method removes all spaces at the beginning and ending of a passed String
String y = splittedCoords[1].trim();
coords = new Coords(Integer.parseInt(x), Integer.parseInt(y)); //Creates new instance of Coords class. x and y are passed as constructor params.
} else {
System.out.println("Format for coords is wrong. You entered '" + coordsEntered + "'.");
}
} catch (NumberFormatException e) { // Integer.parseInt throws an exception if the string does not contain parsable integer.
// We catch an exception and handle it by writing a message
System.out.println("Coords are supposed to be numbers... You entered '" + coordsEntered + "'.");
}
return coords;
}
Also Set is more applicable in this case. Set contains no duplicate elements and Set.contains() method works faster then List.contains(). But if you want to use Set you should implement both equals() and hashCode() methods.
You want to loop if the coords are invalid or already fired.
So shouldn't the while condition be:
while(!validateCoords(coordsEntered)
|| coordsFiredAt(coordsEntered, coordsFired))

How to freely traverse the elements in a two-dimensional array by cardinal direction? (DOWN, UP, LEFT, RIGHT)

This question is about figuring the path through a maze, as is represented by a two-dimensional array. For example, the path through this maze
0 1 2 3 4
---------
0| 1 0 1 1 1
1| 1 0 0 0 1
2| 1 0 1 0 1
3| 1 1 1 0 1
4| 1 1 1 0 1
is
START: [0,1]
Down: [1,1]
Right: [1,2]
Right: [1,3]
Down: [2,3]
Down: [3,3]
Down: [4,3]
The poster was attempting to do this purely with recursion, and actually posted four different questions about it within five hours--which speaks to its complexity.
This got me thinking of the more generic question: How do you freely move around the elements in a two-dimensional array, in any cardinal direction? DOWN, UP, LEFT, RIGHT
If this problem can be solved, then traversing a maze would be much easier.
I solved this with two classes, and an Enum.
First, the enum, which defines the direction you want to move and determines the new indexes, one-at-a-time, based on its movement.
enum Direction {
UP(-1, 0),
DOWN(1, 0),
LEFT(0, -1),
RIGHT(0, 1);
private final int rowSteps;
private final int colSteps;
private Direction(int rowSteps, int colSteps) {
this.rowSteps = rowSteps;
this.colSteps = colSteps;
}
public int getNewRowIdx(int currentRowIdx) {
return (currentRowIdx + getRowSteps());
}
public int getNewColIdx(int currentColIdx) {
return (currentColIdx + getColSteps());
}
public int getRowSteps() {
return rowSteps;
}
public int getColSteps() {
return colSteps;
}
};
The main class is called GridPosition (below). First you set the double-array grid into it, via its int[][] constructor, and store that instance statically:
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
(This step could be designed better, but it works. Also, it should accept any type.)
After setting the grid (which is a one-time-only thing, per-execution), then the x/y constructor is used to declare an initial position:
GridPosition pos = new GridPosition(0, 0);
And after that, just move as necessary:
pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.RIGHT);
pos = pos.getNeighbor(Direction.DOWN);
...
The value of each position is retrieved by pos.getValue(). (As an aside: The huge 2d-array used for the maze--at the bottom of this post, in the "full code"--should really contain one-bit booleans, instead of 4-byte ints, but looking at the array's code makes sense with ints, and doesn't with booleans... Note that it should at least be changed to bytes.)
So regarding movement, if you attempt to get a neighbor when there is none, such as moving left at the left edge, an IllegalStateException is thrown. Use the is*Edge() functions to avoid this.
The GridPosition class also has a convenient debugging function called getNineByNine(), which returns a 9x9 grid of the array values (as a string), where the middle item is the current position.
import java.util.Arrays;
import java.util.Objects;
class GridPosition {
//state
private static int[][] GRID;
private final int rowIdx;
private final int colIdx;
//internal
private final int rowIdxMinus1;
private final int colIdxMinus1;
public GridPosition(int[][] GRID) {
if(this.GRID != null) {
throw new IllegalStateException("Grid already set. Use x/y constructor.");
}
GridPosition.GRID = GRID;
//TODO: Crash if null or empty, or sub-arrays null or empty, or unequal lengths, or contain anything but 0 or -1.
rowIdx = -1;
colIdx = -1;
rowIdxMinus1 = -1;
colIdxMinus1 = -1;
}
public GridPosition(int rowIdx, int colIdx) {
if(GridPosition.GRID == null) {
throw new IllegalStateException("Must set grid with: new GridPosition(int[][]).");
}
if(rowIdx < 0 || rowIdx >= GridPosition.getRowCount()) {
throw new IllegalArgumentException("rowIdx (" + rowIdx + ") is invalid.");
}
if(colIdx < 0 || colIdx >= GridPosition.getColumnCount()) {
throw new IllegalArgumentException("colIdx (" + colIdx + ") is invalid.");
}
this.rowIdx = rowIdx;
this.colIdx = colIdx;
rowIdxMinus1 = (rowIdx - 1);
colIdxMinus1 = (colIdx - 1);
}
public int getValue() {
return GridPosition.GRID[getRowIdx()][getColumnIdx()];
}
public int getRowIdx() {
return rowIdx;
}
public int getColumnIdx() {
return colIdx;
}
public GridPosition getNeighbor(Direction dir) {
Objects.requireNonNull(dir, "dir");
return (new GridPosition(
dir.getNewRowIdx(getRowIdx()),
dir.getNewColIdx(getColumnIdx())));
}
public GridPosition getNeighborNullIfEdge(Direction dir) {
if(isEdgeForDirection(dir)) {
return null;
}
return getNeighbor(dir);
}
public int getNeighborValueNeg1IfEdge(Direction dir) {
GridPosition pos = getNeighborNullIfEdge(dir);
return ((pos == null) ? -1 : pos.getValue());
}
public static final int getRowCount() {
return GRID.length;
}
public static final int getColumnCount() {
return GRID[0].length;
}
public boolean isEdgeForDirection(Direction dir) {
Objects.requireNonNull(dir);
switch(dir) {
case UP: return isTopEdge();
case DOWN: return isBottomEdge();
case LEFT: return isLeftEdge();
case RIGHT: return isRightEdge();
}
throw new IllegalStateException(toString() + ", dir=" + dir);
}
public boolean isLeftEdge() {
return (getColumnIdx() == 0);
}
public boolean isTopEdge() {
return (getRowIdx() == 0);
}
public boolean isBottomEdge() {
return (getRowIdx() == rowIdxMinus1);
}
public boolean isRightEdge() {
return (getColumnIdx() == colIdxMinus1);
}
public String toString() {
return "[" + getRowIdx() + "," + getColumnIdx() + "]=" + getValue();
}
public String getNineByNine() {
int[][] nineByNine = new int[3][3];
//Middle row
nineByNine[1][1] = getValue();
nineByNine[1][0] = getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[1][2] = getNeighborValueNeg1IfEdge(Direction.RIGHT);
//Top
GridPosition posUp = getNeighborNullIfEdge(Direction.UP);
if(posUp != null) {
nineByNine[0][0] = posUp.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[0][1] = posUp.getValue();
nineByNine[0][2] = posUp.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
//Bottom
GridPosition posDown = getNeighborNullIfEdge(Direction.DOWN);
if(posDown != null) {
nineByNine[2][0] = posDown.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[2][1] = posDown.getValue();
nineByNine[2][2] = posDown.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
String sLS = System.getProperty("line.separator", "\r\n");
return "Middle position in 9x9 grid is *this*: " + toString() + sLS +
Arrays.toString(nineByNine[0]) + sLS +
Arrays.toString(nineByNine[1]) + sLS +
Arrays.toString(nineByNine[2]);
}
}
Here's a demo usage:
public class GridPosDemo {
private static final int[][] GRID = new int[][] {
//mega grid goes here...
};
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
public static final void main(String[] ignored) {
GridPosition pos = new GridPosition(0, 0);
System.out.println("start: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.LEFT);
System.out.println("left: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
System.out.println(pos.getNineByNine());
}
}
Output
[C:\java_code\]java GridPosDemo
start: [0,0]=1
right: [0,1]=1
right: [0,2]=1
down: [1,2]=1
down: [2,2]=1
right: [2,3]=1
down: [3,3]=0
left: [3,2]=1
up: [2,2]=1
up: [1,2]=1
Middle position in 9x9 grid is *this*: [1,2]=1
[1, 1, 1]
[0, 1, 0]
[0, 1, 1]
In order to use this for traversing the correct path through a maze, this needs "collision detection" added to it (so it doesn't go through walls), in addition to something to keep track of where you've been (so you don't end up back at the start-position). Such as with some getNeighborIfNotWall(Direction) and isWallToLeft() functions.
Putting aside the maze-question, I would do the following before considering these classes complete:
Make the array-type generic, instead of ints
Add error checking, as documented in the code
Re-design how you set the grid.
Add diagonal directions: UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT
Add the ability to move multiple steps in one direction: getNeighbor(3, Direction.DOWN)
Here's the entire source-code file, containing all of the above (including the mega-maze grid):
//Needed only by GridPosition
import java.util.Arrays;
import java.util.Objects;
enum Direction {
UP(-1, 0),
DOWN(1, 0),
LEFT(0, -1),
RIGHT(0, 1);
//config
private final int rowSteps;
private final int colSteps;
private Direction(int rowSteps, int colSteps) {
this.rowSteps = rowSteps;
this.colSteps = colSteps;
}
public int getNewRowIdx(int currentRowIdx) {
return (currentRowIdx + getRowSteps());
}
public int getNewColIdx(int currentColIdx) {
return (currentColIdx + getColSteps());
}
public int getRowSteps() {
return rowSteps;
}
public int getColSteps() {
return colSteps;
}
};
class GridPosition {
//config
private static int[][] GRID;
private final int rowIdx;
private final int colIdx;
//internal
private final int rowIdxMinus1;
private final int colIdxMinus1;
public GridPosition(int[][] GRID) {
if(this.GRID != null) {
throw new IllegalStateException("Grid already set. Use x/y constructor.");
}
GridPosition.GRID = GRID;
//TODO: Crash if null or empty, or sub-arrays null or empty, or unequal lengths, or contain anything but 0 or -1.
rowIdx = -1;
colIdx = -1;
rowIdxMinus1 = -1;
colIdxMinus1 = -1;
}
public GridPosition(int rowIdx, int colIdx) {
if(GridPosition.GRID == null) {
throw new IllegalStateException("Must set grid with: new GridPosition(int[][]).");
}
if(rowIdx < 0 || rowIdx >= GridPosition.getRowCount()) {
throw new IllegalArgumentException("rowIdx (" + rowIdx + ") is invalid.");
}
if(colIdx < 0 || colIdx >= GridPosition.getColumnCount()) {
throw new IllegalArgumentException("colIdx (" + colIdx + ") is invalid.");
}
this.rowIdx = rowIdx;
this.colIdx = colIdx;
rowIdxMinus1 = (rowIdx - 1);
colIdxMinus1 = (colIdx - 1);
}
public int getValue() {
return GridPosition.GRID[getRowIdx()][getColumnIdx()];
}
public int getRowIdx() {
return rowIdx;
}
public int getColumnIdx() {
return colIdx;
}
public GridPosition getNeighbor(Direction dir) {
Objects.requireNonNull(dir, "dir");
return (new GridPosition(
dir.getNewRowIdx(getRowIdx()),
dir.getNewColIdx(getColumnIdx())));
}
public GridPosition getNeighborNullIfEdge(Direction dir) {
if(isEdgeForDirection(dir)) {
return null;
}
return getNeighbor(dir);
}
public int getNeighborValueNeg1IfEdge(Direction dir) {
GridPosition pos = getNeighborNullIfEdge(dir);
return ((pos == null) ? -1 : pos.getValue());
}
public static final int getRowCount() {
return GRID.length;
}
public static final int getColumnCount() {
return GRID[0].length;
}
public boolean isEdgeForDirection(Direction dir) {
Objects.requireNonNull(dir);
switch(dir) {
case UP: return isTopEdge();
case DOWN: return isBottomEdge();
case LEFT: return isLeftEdge();
case RIGHT: return isRightEdge();
}
throw new IllegalStateException(toString() + ", dir=" + dir);
}
public boolean isLeftEdge() {
return (getColumnIdx() == 0);
}
public boolean isTopEdge() {
return (getRowIdx() == 0);
}
public boolean isBottomEdge() {
return (getRowIdx() == rowIdxMinus1);
}
public boolean isRightEdge() {
return (getColumnIdx() == colIdxMinus1);
}
public String toString() {
return "[" + getRowIdx() + "," + getColumnIdx() + "]=" + getValue();
}
public String getNineByNine() {
int[][] nineByNine = new int[3][3];
//Middle row
nineByNine[1][1] = getValue();
nineByNine[1][0] = getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[1][2] = getNeighborValueNeg1IfEdge(Direction.RIGHT);
//Top
GridPosition posUp = getNeighborNullIfEdge(Direction.UP);
if(posUp != null) {
nineByNine[0][0] = posUp.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[0][1] = posUp.getValue();
nineByNine[0][2] = posUp.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
//Bottom
GridPosition posDown = getNeighborNullIfEdge(Direction.DOWN);
if(posDown != null) {
nineByNine[2][0] = posDown.getNeighborValueNeg1IfEdge(Direction.LEFT);
nineByNine[2][1] = posDown.getValue();
nineByNine[2][2] = posDown.getNeighborValueNeg1IfEdge(Direction.RIGHT);
}
String sLS = System.getProperty("line.separator", "\r\n");
return "Middle position in 9x9 grid is *this*: " + toString() + sLS +
Arrays.toString(nineByNine[0]) + sLS +
Arrays.toString(nineByNine[1]) + sLS +
Arrays.toString(nineByNine[2]);
}
}
public class GridPosDemo {
private static final int[][] GRID = new int[][] {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
{1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},
{1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1},
{1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1},
{1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1},
{1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1},
{1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
{1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1},
{1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1},
{1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1},
{1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1},
{1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1},
{1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1},
{1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1},
{1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1},
{1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1}};
private static final GridPosition GRID_HOLDER = new GridPosition(GRID);
public static final void main(String[] ignored) {
GridPosition pos = new GridPosition(0, 0);
System.out.println("start: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.RIGHT);
System.out.println("right: " + pos);
pos = pos.getNeighbor(Direction.DOWN);
System.out.println("down: " + pos);
pos = pos.getNeighbor(Direction.LEFT);
System.out.println("left: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
pos = pos.getNeighbor(Direction.UP);
System.out.println("up: " + pos);
System.out.println(pos.getNineByNine());
}
}

Can anyone tell me how to improve the run time of this code?

I have written a program to solve Diophantine equations in the form
A5 + B5 + C5 + D5 + E5 = 0;
It should run in N3long(N) time, but it usually takes about 10 minutes for an input size of 100. Can anyone tell me whats wrong?
public class EquationSolver {
//Solves Equations of type: A^5 + B^5 + C^5 + D^5 + E^5 = F^5
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter a max value: ");
int N = input.nextInt();
long START_TIME = System.nanoTime();
SLinkedList test = new SLinkedList();
SLinkedList test2 = new SLinkedList();
test = setupLeftList(N);
test2 = setupRightList(N);
System.out.println("Note: This program takes about 7 minutes to complete for input of 100");
test = mergeSort(test);
test2 = mergeSort(test2);
long END_TIME2 = System.nanoTime() - START_TIME;
System.out.println("Total Time:" + END_TIME2/1000000000.0);
checkEquality(test, test2);
long END_TIME3 = System.nanoTime() - START_TIME;
System.out.println("Total Time:" + END_TIME3/1000000000.0);
}
public static SLinkedList setupLeftList(long boundary)
{
//Creates and returns an linkedList of all possible A,B,C values and their sums
SLinkedList leftSums = new SLinkedList();
for(long c = 0; c < boundary; c++)
{
for(long b = 0; b < c; b++)
{
for(long a = 0; a < b; a++)
{
long sum = (long)(Math.pow(a+1,5)) + (long)(Math.pow(b+1, 5)) + (int)(Math.pow(c+1, 5));
Node current = new Node (sum, a+1, b+1, c+1, null);
//System.out.println(sum);
leftSums.addLast(current);
}
}
}
return leftSums;
}
public static SLinkedList setupRightList(long boundary)
{
//Creates and returns an linkedList of all possible D,E,F values and their sums
SLinkedList rightSums = new SLinkedList();
for(int f = 0; f < boundary; f++)
{
for(int e = 0; e < f; e++)
{
for(int d = 0; d < e; d++)
{
long sum = (long)(Math.pow(f+1, 5)) - ((long)(Math.pow(d+1, 5)) + (long)(Math.pow(e+1,5)));
Node current = new Node (sum, d+1, e+1, f+1, null);
//System.out.println(current.getSum());
rightSums.addLast(current);
}
}
}
return rightSums;
}
public static SLinkedList mergeSort(SLinkedList sums)
// Sorts each list by the value of the sum
{
if (sums.length() > 1 )
{
SLinkedList[] splitList = split(sums);
SLinkedList s1 = mergeSort(splitList[0]);
SLinkedList s2 = mergeSort(splitList[1]);
sums = merge(s1, s2);
}
return sums;
}
public static SLinkedList[] split(SLinkedList sums)
{
// Splits a linked list into two (somewhat) equal halves
long midpoint = sums.length()/2;
Node midPoint = sums.elementAt(midpoint);
SLinkedList s1 = new SLinkedList(sums.head, midPoint, midpoint);
SLinkedList s2 = new SLinkedList(midPoint, sums.tail, midpoint);
SLinkedList[] both = new SLinkedList[]{s1, s2};
return both;
}
public static SLinkedList merge(SLinkedList s1, SLinkedList s2)
{
// Merges two sorted lists of elements
SLinkedList sMerged = new SLinkedList();
while(!s1.isEmpty() && !s2.isEmpty())
{
if (s1.getFirst().getSum() < s2.getFirst().getSum())
{
sMerged.addLast(s1.removeFirst());
}
else
{
sMerged.addLast(s2.removeFirst());
}
}
while(!s1.isEmpty())
{
sMerged.addLast(s1.removeFirst());
}
while(!s2.isEmpty())
{
sMerged.addLast(s2.removeFirst());
}
return sMerged;
}
public static void checkEquality(SLinkedList left, SLinkedList right)
{
// Checks two linked lists for nodes that contain the same Sum value
boolean ans = false;
while (left.isEmpty() == false && right.isEmpty() == false)
{
long currentLeft = left.getFirst().getSum();
long currentRight = right.getFirst().getSum();
if (currentLeft > currentRight)
{
right.removeFirst();
}
else if(currentLeft < currentRight)
{
left.removeFirst();
}
else
{
if (left.getFirst().getC() <= right.getFirst().getA())
{
System.out.println("Answer Found: " + "A: " + left.getFirst().getA() + " B: " + left.getFirst().getB() + " C: "
+ left.getFirst().getC() + " D: " + right.getFirst().getA() + " E: " + right.getFirst().getB() + " F: " + right.getFirst().getC());
ans = true;
}
Node temp = left.getFirst().getNext();
while (temp.getSum() == currentRight)
{
if (temp.getC() <= right.getFirst().getA())
{
System.out.println("Answer Found: " + "A: " + left.getFirst().getA() + " B: " + left.getFirst().getB() + " C: "
+ left.getFirst().getC() + " D: " + right.getFirst().getA() + " E: " + right.getFirst().getB() + " F: " + right.getFirst().getC());
ans = true;
}
temp = temp.getNext();
}
right.removeFirst();
left.removeFirst();
}
}
if (ans == false)
{
System.out.println("No answer found.");
}
}
}
The definitive answer is: use a profiler and see what causes a bottleneck...
But I see you have Math.pow() calls, all with longs, and their 5th power.
You could do it quicker, while even detecting the overflow:
public static long pow5(long base) {
if(base <=6208 && base >=-6208) {
return base*base*base*base*base;
} else {
throw new IllegalArgumentException("Overflow!");
}
}
(Magic number disclaimer: 62085 is ~263, is a number is bigger than that, the 5th power won't fit into 64 bits...)
Math.pow uses doubles, which means a lot of conversion in itself...
Also, #Floris pointed out that it is not even worth computing this over and over again - it could be put into a nice array, and just index that
public static long[] pow5 = getPow5(100);
public static long[] getPow5(long numElements) {
long[] toReturn = new long[numElements];
for(long i=0;long<numElements;long++) {
toReturn[i] = i*i*i*i*i;
}
return toReturn;
}
And where needed, instead of Math.pow(x, 5) just use pow5[x]

Categories