Photo by Piotr Guzik on Unsplash
Using 2D arrays to randomly position "ships" in Battleships
How to use Java's Random class for this without getting overlapping coordinates
I think I'll write a Battleships game...
Here’s an interesting problem: when writing a console application version of “Battleships” in Java, how do you make the ships appear in a random position on the board every time you start a new game?
I had this problem recently when I decided to create said Battleships game. I had no guidance on how to go about this, so designed it myself from scratch. The initial part of the program was easy – drawing the board and updating it with a user’s chosen coordinates. I drew a 10x10 board using a two-dimensional array, mapped a-j to 1-10 in a hashmap, made sure that a user’s input was a valid coordinate, and then just compared the numbers in the coordinate (minus one on both, as the 2D array indices started at 0, so a,9 (1,9) became 0,8) with the numbers in the 2D array. If there was a match, that part of the array would update with an “x”.
Then I created the “ships” with set numbers and put them in their own 2D array. If a user’s coordinate matched a ship’s coordinate, the board would update that coordinate with a “!”. If there were 17 of these “hits”, you’ve won!
Now I knew it was working, the problem became: how do I get the ships to move to random (or at least semi-random) positions when a new game started?
Overlapping coordinates
Initially, I created variables for the 5 different ships and used the Random class randomInt()
number generator to assign a number between 1 and 10 to them, making sure the numbers were all unique using if statements and while loops. Then I used ascending numbers between 1 and 10 to make the ships the correct length. I also created a “coin flip” (random number, 1 or 2) which changed the orientation of the ships – half were placed vertically, half horizontally, and I’d flip them around based on what the “coin” did. So, a “cruiser”, which was 5 squares long, with a randomInt
assigned number of 4, may be:
{4,1},
{4,2}, {4,3}, {4,4}, {4,5}
But I was getting overlapping ships with this solution. I knew the problem lay with my “ships” array but wasn’t sure what was going wrong. So, I put breakpoints at each ship number assignment and a breakpoint at the ship array and looked at what was happening.
The problem was that, because my random starting numbers were between 1 and 10, and I had to assign ascending numbers between 1 and 10, I couldn’t guarantee that coordinates would not repeat. So if I had
{submarine, 1}, {submarine, 2}, {submarine, 3}, {4, destroyer}, {5, destroyer}
And “submarine” was randomly assigned with the number 5 and “destroyer” randomly with the number 1, then I had overlapping ships.
Solution
I either had to make all my ships face one way (horizontally or vertically) or I needed to change how I was assigning numbers. Having all ships face one way would be boring and not reflective of the actual game, so I separated the two groups of numbers. The random starting points stored in the named ship variables would be given numbers 1-5, and the ascending positioning numbers would only be taken from numbers 6-10.
There is no doubt a more elegant solution, which allows more movement around the board for the ships. But for now, I have a working Battleships game. The next step would be making it nicer to look at and play as a web app with a Java framework.
For anyone who would like to look at the source code, it is on my GitHub account here: