So I am making a simple battle ships game (I am fairly new to java...) and I am getting an unexpected result when assigning the locations of 'ships' to a virtual grid of 7x7. I'll start with showing the test code and the output from that code:
Ship[] ships = new Ship[2];
for (int i = 0; i < ships.length; i++) {
ships[i] = new Ship();
ships[i].setLocationCells(ShipLocations.createLocations());
System.out.println(Arrays.deepToString(ships[i].getLocationCells()));
}
for (int i = 0; i < ships.length; i++) {
System.out.println(Arrays.deepToString(ships[i].getLocationCells()));
}
System.out.println(Arrays.deepToString(ShipLocations.getUsedLocations()));
So I am just initializing an array that holds two Ship objects. I loop through and create those objects. ShipLocations.createCells() returns a 3x2 2D array of random unique locations. Set and get methods are pretty standard. The output of this code is this:
[[1, 3], [1, 4], [1, 5]]
[[4, 5], [5, 5], [6, 5]]
[[4, 5], [5, 5], [6, 5]]
[[4, 5], [5, 5], [6, 5]]
[[1, 3], [1, 4], [1, 5], [4, 5], [5, 5], [6, 5]}
So it appears from this that when it is initially set, the positions are indeed unique but in the second for loop where I go back to check the locations, it appears that both object's location cells have been set to the last values generated from ShipLocations.createLocationCells(). The last print is showing all the locations that have created and stored by ShipLocations (as you can see those values are unaffected and still unique). So what is going on here? Why is the last call to setLocationCells() resetting the member variable for both Ship() instances? I am wondering if there is a reference pointer problem here that I am just missing somehow... Do the ship reference variables point to the same object and that's what is happening? Here is the Ship class if that helps with any clarification questions:
import java.util.Arrays;
public class Ship {
private int len = 3;
private int[][] locationCells = new int[3][2];
private int numOfHits = 0;
public String check(int[] g) {
// compare user guess to location cell
for (int i = 0; i < locationCells.length; i++) {
//look for hit, if guess is a location...
if (locationCells[i][0] == g[0] && locationCells[i][1] == g[1]) {
// increase num of hits
numOfHits++;
// shrink locationsCells and remove the hit location
shrinkLocations(g);
if (locationCells.length == 0) {
return "kill";
}
else {
return "hit";
}
}
}
return "miss";
}
public void shrinkLocations(int[] guess) {
int[][] temp = new int[locationCells.length - 1][2];
int currentPos = 0;
for (int i = 0; i < locationCells.length; i++) {
if (!(locationCells[i][0] == guess[0] && locationCells[i][1] == guess[1])) {
temp[currentPos] = locationCells[i];
currentPos++;
}
}
setLocationCells(temp);
}
public void setLocationCells(int[][] locations) {
this.locationCells = locations;
}
public int[][] getLocationCells() {
return this.locationCells;
}
public void setLen(int len) {
this.len = len;
}
public int getLen() {
return len;
}
public int getNumOfHits() {
return numOfHits;
}
}
Here is the ShipLocations class (by request):
mport java.util.Random;
public class ShipLocations {
// array that holds the nine total ship locations
private static int len = 3;
private static int[][] usedLocations = new int[9][2];
private static int[][] shipLocations = new int[len][2];
public static int[][] createLocations(){
// need to know if you are going to position ship up or down.
Random randint = new Random();
// control boolean for do-while loop below
boolean locationsHaveBeenUsed = false;
boolean placementIsValid = false;
int xLoc;
int yLoc;
int direction = randint.nextInt(2);
// generate locations until the initial location isnt already used
do {
// x location starts at 1 and goes to a point where it will still fit on the board
xLoc = randint.nextInt(8 - len) + 1;
// y location starts at 1 and goes to a point where it will still fit on the board
yLoc = randint.nextInt(8 - len) + 1;
locationsHaveBeenUsed = hasBeenUsed(xLoc, yLoc);
//generate new direction and try again.
direction = randint.nextInt(2);
placementIsValid = validPlacement(xLoc, yLoc, direction);
// only place if the locations have not been NOT been used
if (placementIsValid && !locationsHaveBeenUsed) {
//make a call to place at those locations.
placeShipLocations(xLoc, yLoc, direction);
}
// stop once both the locations haven't been used and the placement is not valid
} while (locationsHaveBeenUsed || !placementIsValid);
// current shipLocations array has been altered, return.
return shipLocations;
}
public static boolean hasBeenUsed(int xLoc, int yLoc) {
for (int[] loc : usedLocations) {
// if the randomly generated location has already been used, generate again.
if (loc[0] == xLoc && loc[1] == yLoc) {
return true;
}
}
// if not found in usedLocaations return false
return false;
}
public static void placeInNonEmpty(int xLoc, int yLoc) {
// add the location to used locations in the slot that is first available (non-double zeros)
for (int j = 0; j < usedLocations.length; j++) {
if (usedLocations[j][0] == 0 && usedLocations[j][1] == 0) {
usedLocations[j][0] = xLoc;
usedLocations[j][1] = yLoc;
break;
}
}
}
public static void placeShipLocations(int x, int y, int direction) {
for (int i = 0; i < len; i++) {
// place in UsedLocations array
placeInNonEmpty(x, y);
// place in current shipLocations
shipLocations[i][0] = x;
shipLocations[i][1] = y;
if (direction == 1) {
// moving location up and down
y++;
}
else {
// moving location left and right
x++;
}
}
}
public static boolean validPlacement(int x, int y, int direction) {
for (int i = 1; i < len; i++) {
if (direction == 1) {
// moving location up and down
y++;
}
else {
// moving location left and right
x++;
}
for (int[] loc : usedLocations) {
// check through each location in usedLocations
if (loc[0] == x && loc[1] == y) {
// moving in that direction is not compatible return false and try again
return false;
}
}
}
// if it makes it through that checking minefield return true.
return true;
}
public static int[][] getUsedLocations() {
return usedLocations;
}
}