Universal TweenEngine several values at once - java

I'm interpolating two values at once with TweetEngine (X and Y position), but only X is updated...
Accessor class:
private static class PersonTweenAccessor implements TweenAccessor<Person> {
public static final int POSITION_XY = 1;
#Override
public int getValues(Person target, int tweenType, float[] returnValues) {
switch(tweenType) {
case POSITION_XY:
returnValues[0] = target.position.x;
returnValues[1] = target.position.y;
return 1;
default:
return -1;
}
}
#Override
public void setValues(Person target, int tweenType, float[] newValues) {
switch(tweenType) {
case POSITION_XY:
target.position.set(newValues[0], newValues[1]);
Gdx.app.log("position", newValues[0] + "," + newValues[1]);
break;
}
}
}
Tween creation:
Gdx.app.log("Tween start", "From (" + position.x + "," + position.y + ") to (" + targetPoint.x + "," + targetPoint.y + ")");
Tween.to(this, PersonTweenAccessor.POSITION_XY, distance / speed)
.target(targetPoint.x, targetPoint.y)
.ease(TweenEquations.easeNone)
.setCallback(positionTweenCallback)
.start(GameWorld.tweenManager);
The output (of the log set in the setter) is this (trimmed to improve readability):
Tween start: From (50.0,20.0) to (283,25)
position: 51.305202,20.0
position: 52.14488,20.0
position: 53.2509,20.0
...
position: 280.70465,20.0
position: 281.80902,20.0
position: 282.85034,20.0
position: 283.0,25.0
As you can see, the first value is interpolated but the second is not, until the last access, where is set to its target value.

Your getValues method needs to return 2, not 1, because you have two values that you are modifying.

Related

Issues with writing a subclass of the Rectangle class in Java

I'm a student working on a project in Java where I need to practice using inheritance by extending the default Rectangle class; the child class MyRectangle needs to have constructors that accept parameters that describe the rectangle's border and fill colors as well as its dimensions. I also need to include getter/setter methods for the border/color attributes, a method that will rotate a rectangle by 180 degrees, and methods to calculate and return the area and perimeter of a rectangle. All of the required methods/fields are described in greater detail in the documentation file:///C:/Users/sweis/Downloads/MyRectangle.html
here, and the output should end up looking like this: https://i.stack.imgur.com/KP7LB.png
I've written some code, but I've gotten a lot of error messages referencing the portion of the program where I actually define the MyRectangle class and set up constructors, including "Non-static variable cannot be referenced from a static context" and "error: cannot find symbol". I'm pretty new at Java so I'm really not sure, but I'm afraid I'm fundamentally misunderstanding something about inheritance, and I'm struggling to resolve these errors on my own. I would really appreciate it if someone could look at what I've written so far and help me understand what I'm doing wrong so I can better understand this concept. Here are the portions that are causing problems:
import java.awt.Rectangle;
class Main {
public static void main(String[] args) {
MyRectangle mr1 = new MyRectangle(0, 0, 4, 2, "blue", "red", true);
MyRectangle mr2 = new MyRectangle(5, 5, 10, 3, "green");
MyRectangle mr3 = new MyRectangle();
System.out.println(mr1 + " " + "area = " + mr1.area() + " perimeter = " + mr1.perimeter());
System.out.println(mr2 + " " + "area = " + mr2.area() + " perimeter = " + mr2.perimeter());
System.out.println(mr3 + " " + "area = " + mr3.area() + " perimeter = " + mr3.perimeter());
System.out.println(mr4 + " " + "area = " + mr4.area() + " perimeter = " + mr4.perimeter());
}
public static class MyRectangle extends Rectangle {
public static int width, height;
public String color, borderColor;
public boolean border;
public MyRectangle() {
super();
}
public MyRectangle(int x, int y, int w, int h, String c) {
width = w;
height = h;
color = c;
}
public MyRectangle(int x, int y, int w, int h, String c, String bc, boolean b) {
borderColor = bc;
border = b;
}
public int area() {
return (width * height);
}
public int perimeter() {
return ((width * 2) + (height * 2));
}
public void setBorder(boolean newBorder) {
border = newBorder;
}
}
}
}
If you have any questions or need me to clarify anything I'll definitely do so. Thank you!
The issue not really with the inheritance here.
Non-static variable cannot be referenced from a static context
As main method is static, it can't access inner non-static class MyRectangle inside it. You have already added static keyword to your MyRectangle class definition so this should fix this issue. You call also move MyRectangle class outside your main class. This would automatically make it static as all "Top level classes are static by default".
There is another issue here, the variables width, height from MyRectangle class are defined as static. This would result in these variables shared across all the different MyRectangle objects that you have created and override each others values. So remove the static keyword from there as they need to be different for each instance.
error: cannot find symbol
Object mr4 is not created but used in the print statements, this would be resulting in cannot find symbol. So just creating this object should fix your issue.
After these fixes your code should look something like:
class Main {
public static void main(String[] args) {
MyRectangle mr1 = new MyRectangle(0, 0, 4, 2, "blue", "red", true);
MyRectangle mr2 = new MyRectangle(5, 5, 10, 3, "green");
MyRectangle mr3 = new MyRectangle();
MyRectangle mr4 = new MyRectangle(); // now mr4 is created
System.out.println(mr1 + " " + "area = " + mr1.area() + " perimeter = " + mr1.perimeter());
System.out.println(mr2 + " " + "area = " + mr2.area() + " perimeter = " + mr2.perimeter());
System.out.println(mr3 + " " + "area = " + mr3.area() + " perimeter = " + mr3.perimeter());
System.out.println(mr4 + " " + "area = " + mr4.area() + " perimeter = " + mr4.perimeter());
}
static class MyRectangle extends Rectangle {
public int width, height; // this should be non static
public String color, borderColor;
public boolean border;
public MyRectangle() {
super();
}
public MyRectangle(int x, int y, int w, int h, String c) {
width = w;
height = h;
color = c;
}
public MyRectangle(int x, int y, int w, int h, String c, String bc, boolean b) {
this(x, y, w, h, c); // this should initialise other args by calling different constructor
borderColor = bc;
border = b;
}
public int area() {
return (width * height);
}
public int perimeter() {
return ((width * 2) + (height * 2));
}
public void setBorder(boolean newBorder) {
border = newBorder;
}
}
}

Printing out most expensive boat and it's information from an array

I am working on a boat program that has a super class (Boat) and two subclasses (SailBoat, Powerboat) and I must print out all of the boats information and price as well as the most expensive boat and it's information alone. This is the part I am having trouble with since I am not entirely sure how to go about it. Here is what I have so far...
Boat Class:
public class Boat {
String color;
int length;
public Boat() {
color = "white";
length = 20;
}
public Boat(String col, int leng) {
color = col;
length = leng;
}
public boolean setColor(String col) {
if ("white".equals(col) || "red".equals(col) || "blue".equals(col) || "yellow".equals(col)) {
col = color;
return true;
} else {
System.out.println("Error: can only be white, red, blue or yellow");
return false;
}
}
public String getColor() {
return color;
}
public boolean setLength(int leng) {
if (leng < 20 || leng > 50) {
leng = length;
System.out.println("Sail Boats can only be between 20 and 50 feet, inclusively.");
return false;
} else {
return true;
}
}
public int getLength() {
return length;
}
public String toString() {
String string;
string = String.format("Color = " + color + " Length = " + length);
return string;
}
public int calcPrice() {
int price;
price = 5000 + length;
return price;
}
}
PowerBoat Subclass
import java.text.NumberFormat;
public class PowerBoat extends Boat {
int engineSize;
public PowerBoat() {
super();
engineSize = 5;
}
public PowerBoat(String col, int len, int esize) {
this.color = col;
this.length = len;
engineSize = esize;
}
public boolean setEngineSize(int esize) {
if (esize < 5 || esize > 350) {
System.out.println(
"Error: That engine is too powerful. The engine size must be between 1 and 350, inclusively");
esize = engineSize;
return false;
} else {
return true;
}
}
public int calcPrice() {
int price;
price = 5000 + length * 300 + engineSize * 20;
return price;
}
public String toString() {
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
return super.toString() + " Engine Size = " + engineSize + " Price = " + nf.format(calcPrice());
}
}
SailBoat subclass
import java.text.NumberFormat;
public class SailBoat extends Boat {
int numSails;
public SailBoat() {
numSails = 0;
}
public SailBoat(String col, int leng, int numsail) {
color = col;
length = leng;
numSails = numsail;
}
public boolean setNumSails(int nsails) {
if (nsails < 1 || nsails > 4) {
nsails = numSails;
return false;
} else {
return true;
}
} // end setNumSails
public int getNumSails() {
return numSails;
}
public int calcPrice() {
int price;
price = length * 1000 + numSails * 2000;
return price;
}
public String toString() {
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
return super.toString() + "Color: " + color + " Length: " + length + " Number Sails = " + numSails + " Cost = "
+ nf.format(calcPrice());
}
public int getTotalCost() {
int totalCost = 0;
totalCost += calcPrice();
return totalCost;
}
}
Inventory class (tester)
import java.util.ArrayList;
public class Inventory {
public static void main(String[] args) {
// boat objects
Boat pb1 = new PowerBoat("blue", 22, 60);
Boat sb1 = new SailBoat("white", 20, 1);
Boat sb2 = new SailBoat("red", 42, 3);
Boat pb2 = new PowerBoat("yellow", 35, 80);
Boat pb3 = new PowerBoat("red", 50, 120);
Boat sb3 = new SailBoat("blue", 33, 2);
Boat pb4 = new PowerBoat("white", 20, 10);
ArrayList<Boat> AL = new ArrayList<Boat>();
// add boat objects to arraylist
AL.add(pb1);
AL.add(sb1);
AL.add(sb2);
AL.add(pb2);
AL.add(pb3);
AL.add(sb3);
AL.add(pb4);
// print all boat objects
System.out.println("Print all boats");
for (Boat anyBoat : AL) {
System.out.println(anyBoat.toString());
}
int max = 0;
int totalcost = 0;
Boat mostExpensiveBoat = null;
for (Boat anyBoat : AL) {
if (anyBoat instanceof SailBoat) {
totalcost += anyBoat.calcPrice();
if (anyBoat.calcPrice() > max) {
max = anyBoat.calcPrice();
mostExpensiveBoat = anyBoat;
}
}
}
}
}
I am really confused on how to finish up this program, the results I am supposed to get after all the boat information is printed is this..
Total price of all boats is $ 170,500.00
Most Expensive Boat: Color = red Length = 42 Number Sails = 3 Cost = $ 48,000.00
Any help will be greatly appreciated. Thank you.
There are a few design flaws you should correct:
Your Boat class should be an interface or abstract. You can't have a boat that isn't a power boat or sail boat so you should not be able to instantiate one.
Your instance variables should be private.
Make methods abstract that need to be defined by subclasses of Boat (e.g. calcPrice).
If you are able to use Java 8 then there's a nice way of getting the most expensive boat. The following code will print the most expensive boat (using Boat.toString) if one is present.
allBoats.stream()
.max(Comparator.comparingInt(Boat::calcPrince))
.ifPresent(System.out::println);
That avoids having to write the code that manually iterates through your list comparing prices. It also copes with the situation of an empty list (which means there is no maximum). Otherwise you need to initialise to null and compare to null before printing.
Your for loop should look like this:
for (Boat anyBoat : AL) {
totalcost += anyBoat.calcPrice();
if (anyBoat.calcPrice() > max) {
max = anyBoat.calcPrice();
mostExpensiveBoat = anyBoat;
}
}
It doesn't matter if it's a sailBoat or not, you just wanna print the information of the most expensive one, so you can remove the instanceof condition. After that:
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
System.out.println("Total price of all boats is " + nf.format(totalcost));
System.out.println("Most expensive boat: " + mostExpensiveBoat.toString());
Should work, since you have already overriden the toString() methods.
one more thing: In your SailBoat toString() method, you are doing:
return super.toString() + "Color: " + color + " Length: " + length + " Number Sails = " + numSails + " Cost = "
+ nf.format(calcPrice());
When you call the super.toString() you are printing the color and the length twice; just call
return super.toString() + " Number Sails = " + numSails + " Cost = " + nf.format(calcPrice());

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

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.

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

toString() and accessors

public class Fan {
public static void main(String[] args){
Fan fan1 = new Fan();
fan1.setSpeed(FAST);
fan1.setRadius(10);
fan1.setColor("yellow");
fan1.setOn(true);
System.out.println(fan1.toString());
}
// fan speed variables
final static int SLOW = 1;
final static int MEDIUM = 2;
final static int FAST = 3;
// Other fan variables
private int speed;
private boolean on; // true means on
private double radius; // radius of fan
String color;
// No-arg constructor
public void Fan(){
speed = SLOW;
on = false;
radius = 5;
color = "blue";
}
// Mutator methods
public void setSpeed(int newSpeed){
if(newSpeed < 0)
System.out.println("Illegal speed!");
else
speed = newSpeed;
}
public void setOn(boolean newOn){
on = newOn;
}
public void setRadius(int newRadius){
if(newRadius < 0)
System.out.println("Illegal radius!");
else
radius = newRadius;
}
public void setColor(String newColor){
color = newColor;
}
// Accessor methods
public int getSpeed(){
return speed;
}
public boolean getOn(){
return on;
}
public double getRadius(){
return radius;
}
public String getColor(){
return color;
}
// toString method to output Fan data
public String toString(){
if(on = false)
return "Fan is off.";
else
return "Fan Properties:\n" + "Fan speed: " + speed + "\n"
+ "Color: " + color + "\n"
+ "Radius: " + radius + "\n";
}
}
The above piece of code is simple but I was wondering how the toString method uses the on variable even though I didn't supply parameters for that method. Also, why do we not need to invoke get methods in the main class and only need to invoke the set methods? (please explain how each method invokes one another until the final output)
Thanks a lot!
As far as you are in this class body you can access everything (except for static can not access non-static). That means that you can easily set and get variables like that:
var = <value>;
System.out.println(var);
However nobody stops you from using the accessor methods - getter and setters. It is just not required.
One final note:
if(on = false)
This will always fail - it does assignment to false and then checks the newly assigned value (which is false). You need to check for equality here. Like that:
if(on == false)
Or even better:
if(!on)
I just copied-pasted your code into a new file and compiled it. It compiled and ran. The output was
$ java Fan
Fan Properties:
Fan speed: 3
Color: yellow
Radius: 10.0
This is because the comparison in your toString method is wrong. It should be as following:
public String toString(){
if(on)
return "Fan Properties:\n" + "Fan speed: " + speed + "\n"
+ "Color: " + color + "\n"
+ "Radius: " + radius + "\n";
else
return "Fan is off.";
}

Categories