Improved ship placement

In order for the player to have a unique experience each time they play, the enemy ship positions need to be randomized each time. (this may have a bit of technical jargon involved)

Posted by on

In order to understand how the ship placement was refined and improved, it is important to understand how the program works. It consists, so far, of two main elements, ships and boards.

## The Board

It is like the board that you play actual battleships on. There's a grid, labelled with X, Y coordinates, and the ships that you and the opponent places take up multiple grid squares.

(As you can see some ships take up 3 squares, some take up 4 etc.)

To represent this in C++, I have created a data structure that consists of (bear with me), a pointer that points to the address of an array of pointers which each point to the address of arrays. Which can be manipulated in certain ways (setting and getting the values at a certain point) and then printed to the screen. If you understand some programming or C++ that might make sense, but if not then it essentially creates something like this:

As you may be able to see, this is quite similar a board that you would play battleships on. To simulate ships will be like the real battleships as well. They will have multiple consecutive parts of the grid represented as a part of the ship. To represent water is simple, I will assign the value 0.

## Ships

To represent ships I could do quite a few things. I could assign the positions of a ship (Since a ship has length it will have multiple grid positions) the value 1. But that won't be good enough to represent separate ships. So I need a way of assigning different values to represent different ships. Let me explain:

A ship needs to have positions (emphasis on the plural) which will be determined by its length and it needs a way to differentiate one ship from another ship. So, each ship will have its own unique value (3, 4, 5, 1006 etc.), its length and its positions.

I created the data structure for ship and simplified this down to, value, length, an origin x-position, origin y-position and of course a name.

Additionally, when dealing with the position, what the program will do is take the initial position of the ship (x, y), assign the value of the ship to that position on the board + all the positions up til it's length.

Basically, as you can see, Test Ship1 has a length of 4, a value of 5 and it's origin position is at (1, 2).

## Placing Ships (finally)

Last night, I spent most of my time getting a system working to place the ships on the board. Many factors had to be taken into account when considering where and how a ship could be placed.

### Array Size Check

If, for example, the size of the board is 10 by 10 (in C++ that means it goes from 0 - 9 in the X direction and 0 - 9 in the Y direction). So my board is 10 grid spaces by 10 grid space, and lets say I want to place a ship with a length of 4 on this board. Okay, let's place the ship at 0, 0.

This seems okay, now what if we place the ship at 6, 0.

This is also, okay. Now, what if we wanted to place the ship at 7, 0. Well, as you may be able to tell, the ship would go over the edge of the board.

So, not only would this not follow the rules of battleship, it would also crash the program. The array in this example only has 10 elements (only 10 grid units long), if you tried to assign a value to the 11th element of an array with 10 elements it would cause an access violation because you would actually be trying to assign a value to a piece of memory that is being used elsewhere in the computer (that next address up isn't assigned to the array). This is a problem, so now I need to check every ship placement to make sure that it won't place a ship more than its own length away from the edge of the array. I've called this the array size check:

If the array size check is not met, it will give an error and try again with a different position.

### Zero Check

If, for example, you have a ship already on the board at 0, 0. Now, you want to place another ship at 4, 0.

This is okay, the two ships are right next to each other. Now, what if you wanted to place another ship at 3, 0 instead of 4, 0.

What happens is, the second ship to be placed (in this case TestShip2[6]), has been placed over the top of the last segment of TestShip1[5]. This won't crash the game however, there is nothing illegal about reassigning legal values. However, in the rules of Battleships you can't place ships with overlapping parts. So, I created the zero check.

The zero check basically only allows a ship and its segments (multiple positions remember) to be assigned to a value that holds zero (aka Water).

### Far Side Check

If, for example, I wanted to place a ship on a board of 10 by 10 grid units, with a length of 4, at 7, 0. Similarly to the array size check, it will check that the original position isn't greater than the distance between the edge of the board minus the length of the ship. However, this function may be removed as usually the array size check already discovers this error before it gets a chance to execute the far side check.

This is the end of this little explanation, I just thought it might be good to express my thinking whilst developing this small project. It's nothing significant, however, I believe articulating my thought process out loud or in writing (even if nobody ends up reading it) allows me to understand what I'm doing better. Already through writing this article and taking the screenshots of the examples, I have found multiple mishaps in the code that I wouldn't have discovered otherwise.

Thank you for reading if you did and goodbye!