0

I'm making battleships and I've currently come across an issue where my ships overlap. I've tried to incorporate an if statement that will judge whether it can be placed. Here's an example of me placing two ships of length 3 down.

public static void PlaceCruiser(String[][] board) {
ThreadLocalRandom random = ThreadLocalRandom.current();

int timesplaced = 0;
int size = 3;


while (timesplaced < 2) {
    int randomcruisercheck =(int)(Math.random()*2);
if (randomcruisercheck == 0) {
    int column = random.nextInt(0,9);
    int row = random.nextInt(0,7);
    if (row + 2 < 11 && board[row][column] == "." && board[row + 1][column] == "." && board[row + 2][column] == ".") {

        for(int i = 0; i<size; i++)
        {

            board[row+i][column] = "#";

            }
        System.out.println(board[row][column]);
        }

    timesplaced++;
    }
    else if (randomcruisercheck == 1) {
        int column = random.nextInt(0,9);
        int row = random.nextInt(0,7);
        if (column + 2 < 11 && board[row][column] == "." && board[row][column + 1] == "." && board[row][column + 2] == ".") {

            for (int i = 0; i<size; i++)
            {
                board[row][column + i] = "#";
                }
            System.out.println(board[row][column]);
        }

        timesplaced++;
    }
}

}

Basically, I use "#" to represent a ship in a 10x10 2D array of ".". I feel like the if statement about if the row or column plus 1 then plus 2 is a dot i.e a free space, a ship will be generated but this does not seem to be the case. Can anyone help me out?

Nedward
  • 17
  • 2
  • 1
    Try printing your indexes before each time you access the board. You'll probably find it that way. – Joseph Larson Dec 04 '19 at 17:46
  • 1
    What do you mean? – Nedward Dec 04 '19 at 19:07
  • Besides the code, when you compare strings you should use `.equals()` Reference: https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java – Juan Franco Dec 04 '19 at 21:45
  • @Nedward add System.out.println statements in your code to print your i and j just before you use them to reference your array. This is the most basic of debugging and an absolutely critical skill. Doing so will help you find your problem. – Joseph Larson Dec 05 '19 at 16:03

2 Answers2

0

Your code works well, you only need to take care of the indexes and initialize the board:

public class Main {

    public static String[][] board;

    public static void main(String[] args) {

       PlaceCruiser pc = new PlaceCruiser();
       board = new String[10][10];

       // Initialize the board
       for (int i=0;i<10;i++) {
          for (int j=0;j<10;j++) {
             board[i][j]=".";
          }
       }

       pc.placeCruiser(board);

       // Show thew board
       for (int i=0;i<10;i++) {
          for (int j=0;j<10;j++) {
             System.out.print(board[i][j]);
          }
          System.out.println();
       }
    }
}

Result:

..........
..###.....
..........
..........
....#.....
....#.....
....#.....
..........
..........
..........

Also check that your initial position is not already "#".

Juan Franco
  • 199
  • 1
  • 7
0

Stylistical remarks:

  • if you use ThreadLocalRandom for generating position, you should also use it for other randomness (in other words: (int)(Math.random()*2) could rather be random.nextBoolean(), because actually a boolean could decide if ship should be horizontal or vertical)
  • nextInt(0,x) is just a longer variant of nextInt(x).

Actual bugs:

  1. due to a presumably copy-paste issue, column (0-"9") and row (0-"7") are generated in the same way in both cases, making it possible to index out of the array when placing a vertical ship
  2. which you seem to have noticed, but fixed it with that row + 2 < 11 check which has two problems in itself:
    1. when row+2 ends up being 10 (which is <11), that is an invalid index (valid indices are 0...9)
    2. as row stays between 0 and "7", there will not be horizontal ships in the last few rows
  3. nextInt(a,b) generates numbers a...b-1, so it will not generate b itself
  4. as the other answer points out string comparison with == generally and usually does not work, use equals()

Generally I would suggest having a single check+placement function, which can deal with an entire rectangle (given position+size). Also, I switched to array of characters, that simplifies both comparisons and printing.

boolean tryPlace(int x,int y,int width,int height) {
  for(int i=0;i<height;i++) {
    for(int j=0;j<width;j++) {
      if(board[y+i][x+j]!='.') {
        return false; // ship can not be placed
      }
    }
  }
  // if we reach here, ship can be placed
  for(int i=0;i<height;i++) {
    for(int j=0;j<width;j++) {
      board[y+i][x+j]='#';
    }
  }
  return true; // ship placed successfully
}

This routine could be called to place a pair of 3-long ships this way:

board=new char[10][10];
for(int i=0;i<10;i++)
  for(int j=0;j<10;j++)
    board[i][j]='.';

int size=3;
int amount=2;
while(amount>0) {
  if(random.nextBoolean()) {
    // horizontal
    if(tryPlace(random.nextInt(10-size+1),random.nextInt(10),size,1)){
      amount--; // one placed
    }
  } else {
    // vertical
    if(tryPlace(random.nextInt(10),random.nextInt(10-size+1),1,size)){
      amount--; // one placed
    }
  }
}

// and a 4x2 mothership
while(!(random.nextBoolean()
  ?tryPlace(random.nextInt(7),random.nextInt(9),4,2)
  :tryPlace(random.nextInt(9),random.nextInt(7),2,4)
));

for(int i=0;i<10;i++)
  System.out.println(board[i]); // char[] has special overload for print/ln()

Test: https://ideone.com/DjYqjB


However, when I was a kid we had a rule that ships could not match, there had to be empty space (or a border of the board) around them. If you need that, tryPlace() could check a larger block, and put the ship into the middle of it. Also, a usual trick of implementing board games is that you can keep a larger array in the memory than what you will actually display. So instead of fighting with "check if field is empty or it is outside the board", it is simpler to have a 12x12 board, and place ships into the middle 10x10 portion of it:
boolean tryPlaceWithBorder(int x,int y,int width,int height) {
  for(int i=0;i<height;i++)
    for(int j=0;j<width;j++)
      if(board[y+i][x+j]!='.')
        return false; // ship can not be placed
  // if we reach here, ship can be placed
  for(int i=1;i<height-1;i++)
    for(int j=1;j<width-1;j++)
      board[y+i][x+j]='#';
  return true; // ship placed successfully
}

and modified usage:

board=new char[12][12];
for(int i=0;i<12;i++)
  for(int j=0;j<12;j++)
    board[i][j]='.';

int size=3;
int amount=2;
while(amount>0) {
  if(random.nextBoolean()) {
    // horizontal
    if(tryPlaceWithBorder(random.nextInt(12-size-1),random.nextInt(10),size+2,3))
      amount--; // one placed
  } else {
    // vertical
    if(tryPlaceWithBorder(random.nextInt(10),random.nextInt(12-size-1),3,size+2)){
      amount--; // one placed
    }
  }
}

// and a 4x2 mothership
while(!(random.nextBoolean()
  ?tryPlaceWithBorder(random.nextInt(7),random.nextInt(9),6,4)
  :tryPlaceWithBorder(random.nextInt(9),random.nextInt(7),4,6)
));

for(int i=1;i<11;i++)
  System.out.println(String.valueOf(board[i],1,10));

Test: https://ideone.com/LXAD7T

tevemadar
  • 12,389
  • 3
  • 21
  • 49