
Project Outline
Time for something a little more light hearted, I think! Battleships is a game I'm sure you'll remember from childhood. It's played by two people, each with a square grid. Both players mark a set number of crosses on squares chosen at random on their grids. The crosses represent the battleships, and each player puts them in positions that the other player is unlikely to choose. The idea, of course, is to bomb your opponent's navy - each player takes turns in choosing a square at random on his/her opponent's board:
"I choose square E4."
"That's a miss. I choose square D7."
"BANG! You've hit a battleship! Now I choose A3."
etc.
The game proceeds until one side's navy is all lying at the bottom of the ocean.


The numbers that refer to the individual numbers (the elements) of the array are called indices (the singular is index). The first index is always 0 - with arrays, you have to count from 0, not from 1 - but you can decide how many elements there will be in the array.
Declare an array exactly as you would a simple variable, except that you must include the number of elements after the name in square brackets [like this].
#include <iostream>
int v[6]; // Declare array of 6 elements (0 to 5)
void main ()
{ v[0] = 304;
v[3] = -20;
v[2] = 56000;
cout << v[0] * v[3] + v[2];
v[4] = v[2] / 400;
v[4]++;
cout << "The 5th value is " << v[4] << endl;
}
The program declares an array with 6 elements, but the highest index is 5 as you start counting from 0. Array elements are used exactly the same way as you would ordinary variables, but remember to include the index of the particular element you are referring to in square brackets. The first line of the main program, for instance sets element 0 of the array to 304.
Arrays are often used with loops. The following program, for example, declares an array, sets all the elements to half the index number (so element 7 will hold 3.5 etc.) and then adds the values together:
#include <iostream>
float numbers[600];
void main()
{ for (int x = 0; x < 600; x++)
numbers[x] = x / 2.0;
// Add the values together
for (x = 0, float sum = 0; x < 600; x++)
sum += numbers[x];
// Display the result:
cout << "The sum is " << sum << endl;
}
Firstly, the loop counter (called x in both cases) is not allowed to reach 600. In fact, the loops terminate as soon as it goes above 599. This is because the highest array index is 599. There are 600 elements, but the first index is 0. Secondly, the array indices can be variables or even arithmetic expressions, providing they yield integers (obviously, an index can't be a decimal number):
float x = 2.0;
int y = 2;
cout << my_array[7 + 2 * x];
// Illegal as x is a floating point number
cout << my_array[7 + 2 * y];
// Legal as y is an integer
You must be careful not to try to access an element which is beyond the limit of the array, for instance:
double small_vals[70]; small_vals[121] = 0.00342;
There is no element 121 in the array! Your version of C++ may produce an error, or it may alter some unexpected area of memory causing the program to crash or produce unexpected results.

The following program declares a two dimensional array and performs some calculations on it. It shows you how to declare and access two-dimensional arrays:
#include <iostream>
long g[9][9]; // Declare the array, 0..8 and 0..8
void main ()
{ g[0][0] = 304;
g[0][1] = 24;
g[0][2] = 149; // Put in extra lines here
g[1][0] = 39;
g[2][0] = 1900; // Ditto
for (int x = 1; x < 9; x++)
for (int y = 1; y < 9; y++)
g[x][y] = g[x][y-1] + g[x-1][y]
}
Two-dimensional arrays are often used with nested loops as in listing 4.3. This program sets the first row and column of the array to certain values and then adds array elements to produce the values for others. In fact, I haven't bothered to put in all the values for the first row and column - that would make the listing a lot longer. Add lines to the program to fill the row and column, and then predict what numbers are entered into the other elements of the array. Then add appropriate cout statements to see if you are correct.
Arrays can have several dimensions - three dimensions represent a "cube" of numbers, four dimensions and higher can't be represented easily on paper but they can exist inside the computer's memory:
cube[2][x+1][y * y - 4] = 30.2; cout << multi[a][b][c][d][e];

char get_code_letter (int codes[])
In the function call itself, the array is specified just by its name, without any square brackets:
cout << "The code letter is " << get_code_letter(c);
In this case, c would be the array. The function has no way of knowing what the dimensions of the array are, so it is a good idea to pass the dimensions across as a separate parameter:
char get_code_letter (int codes[], int max)
Now the code in the function can be rewritten so that it does not try to access an array element outside the range 0 to max.
What about passing multidimensional arrays to a function?
Good question! In this case, it is really necessary to specify in the function definition exactly what the dimensions are. For example, if you were passing a 10-by-10 array, the function would start:
void transform (float my_grid[10][10])
In this case, the array would be referred to as my_grid inside the function and would have a maximum index of 9 (not 10) in both directions. It does look almost as though you are passing a single array element across, but you must remember that you can't write a single array element in the parameter list of a function, although you can pass one across when the function is called, of course:
transform(matrix); // This passes the whole 10-by-10 array test_positive(matrix[3][7]); // This just passes one element across
int x = 45;
The same applies to arrays. In this case, enclose the value (or values) in curly brackets:
float currency_rate[4] = {2.0, 2.05, 1.9, 1.87};
This declares an array called currency_rate with four elements, and sets currency_rate[0] to 2.0, currency_rate[1] to 2.05 etc. The line must end in a semicolon as usual. If you miss out any numbers, the remaining elements are set to 0:
float factor[10] = {30.1, -34.2};
In this case, factor[0] is set to 30.1, factor[1] is set to -34.2 and all the other elements are set to 0. The simplest way to set an entire array to 0 is as follows:
int build_up[300] = {0};
You can even miss out the number 0 entirely - the following also fills the array with 0:
int build_up[300] = {};
One other variation is to miss out the numbers that specify the dimensions and let the compiler calculate it from the declaration itself:
int vals[] = {3, 2, 2, 5, 1, 6, 7};
The compiler declares an array of 7 elements (indices 0 to 6) as 7 values are presented. The following statement would, however, be illegal, as the compiler has no way of calculating the size of the array to be declared:
int silly[] = {}; // Illegal!
Two dimensional arrays can be declared in a similar way, although a set of curly brackets is needed for each row of the array:
int v[3][3] = { { 1, 2, 3 }, {4, 5, 6}, {7, 8, 9} };
Each set of curly brackets specifies another row, with commas separating them. In this case, v[0][0] is initialised to 1, v[0][1] to 2 etc. With longer rows, it makes it easier to read if the rows are specified on different lines:
int big[100][100] = {{3, 2, 2, 9, 4, 6, 3, 2, 4, 5} ,
{4, 2, 10 } };
In this case, big[0][0] is set to 3, big[1][2] to 100, but all the elements higher than big[1][9] are set to 0. I will leave you to work out what the values contained in big[1][3], big[1][4] etc. are. If you had missed out the numbers that specified the size of the array ...
int big[][] = {{3, 2, 2, 9, 4, 6, 3, 2, 4, 5} ,
{4, 2, 10 } };
... the compiler would have assumed that big[1][9] was the highest element required and would not have declared any elements higher than this.
Whichever way your version of C++ calculates pseudo-random numbers, you can guarantee that it uses a seed number. This is the number on which the first random number is based. The number produced is then used as the seed for the next calculation. Although the numbers appear random, if you give the computer the same seed, it will produce the same sequence of numbers.
The usual way to produce random numbers is to include a standard header file in your program. So far, you have met the header file iostream.h and have included it using the instruction #include<iostream> (or #include<iostream.h> on some systems). There are several others to choose from as well. The random number generator, rand(), is present in the file cstdlib.h so this must also be included:
#include<iostream>
#include<cstdlib>
int x = 0;
void main()
{ cout << "Here are 10 random numbers : ";
for (int count = 1; count <= 10; count++)
cout << rand(100) << " ";
cout << endl;
}
The function takes one parameter which is always 1 more than the maximum value of the random number, so calling rand(100) produces a random number in the range 0 to 99 inclusive (but not 100). You don't need to set up the seed for the random number generator, as C++ does that for you.
You may need to change cstdlib to cstdlib.h on your system. In a later project, I will show you how to write your own header files containing program code which you want to make available to different programs.
There are other routines present in cstlib, for instance, a routine to find the absolute value of a number (i.e. make it positive if it is negative). Your version of C++ should have a Help facility which will list and explain the functions available in each standard header file.
If a variable is declared inside a function or a block of statements (for instance in a loop), then it only exists within that function or statement block. This is the lifetime of the variable - it comes into existence the moment it is declared and ceases to exist when the block comes to an end. In practice, this means the curly brackets that start and end the block:
void my_func ()
{ char hello = 'X';
// Variable hello is "born" here
int a = 0;
// Variable a is "born" here
// Variable xyz does not exist yet
do
{ int xyz = 0;
// Variable xyz is "born" here
// Variables hello and a also exist
cin >> a;
}
while (a <= 10);
// Variable xyz no longer exists
}
// Variables hello and a no longer exist.
As the program passes beyond the } symbols, variables "die". If you tried to access the variable xyz in the code segment above outside the do-while loop, for example, the compiler could object.
C++ can't cope with more than one variable with the same name active at any one time. This means that if a variable exists outside a block of statements or a function, and a variable with the same name is declared inside that block of statements, the outer variable is disabled while the variable local to the block is active. Once the block finishes, the local variable is destroyed and the outer variable is then "reactivated".
In the following function definition, a variable x is declared at the start and then another one later on. The first variable x (set to 2) is disabled while the new x is active and then reappears after that block of statements is over:
int silly (float v1)
{ // parameter v1 exists throughout the function
int x = 2;
cout << "x is " << x << endl;
if (x > 1)
{ int x = 450;
cout << "x is now " << x << endl;
}
cout << "Finally x is " << x << endl;
}
x is 2
x is now 450
Finally x is 2
Of course, the parameter v1 can be referred to through the function, although when the function terminates, v1 ceases to have any meaning. If there had been a variable called x (or v1 for that matter) in the function that called this one (or the main program), then it too would have been "locked away" while this function executed.
The concept of variable scope can prove quite useful. For instance, you can write a function containing its own variables and not worry about whether the main program contains variables with the same name. Useful variable names like "count" can be reused without confusion. It enables you to write functions which can be included in someone else's programs.
Of course, this declaring of variables which are local to a block is not limited to functions. You can declare variables which are local to loops in the main program, although, that too is in a function - the special function called main().
#include <iostream>
void main ()
{ char letter = 'A';
int x = letter; // Set integer to char variable
cout << letter << endl;
cout << x << endl;
}
The integer variable x is set to the number representing the character variable letter. When letter is displayed, it appears as A. When x is displayed, it appears as 65, the number used to store A in the computer.
Almost all computers store characters using a standard code called ASCII (pronounced "Askee") - American Standard Code for Information Interchange. This defines a series of characters from 0 up to 127. The first 32 numbers (0 to 31) are used to store control codes (such as new line or "Escape") with the printable characters starting at 32 (the "space" character - equivalent to a space obtained by pressing the space bar). The digits start at 48 (for "0"), 49 (for "1") etc. Capital letters start at 65 ("A"), 66 ("B") etc. and small letters at 97 ("a"), 98 ("b") etc. The other numbers are used to store various other punctuation symbols.
The following program displays all the printable characters in the ASCII set. In this program the conversion is done the other way. The for loop contains an integer variable counting from 32 to 127, which is converted to a character:
#include <iostream>
void main ()
{ for (int x = 32; x <= 127; x++)
{ char m = x;
// Variable m only exists within this loop
cout << x << " " << m << endl;
}
}
There is another, less commonly used, code for representing characters called EBCDIC. You should check to see whether your personal computer uses this code.
Make sure that the numbers are written out with an appropriate format, i.e. that they are lined up in columns rather than just spilling out onto the screen.
char a1 = 'A', a2 = 'a', z1 = 'Z', z2 = 'z'; int some_number = a1 * a2 + z1 * z2; cout << some_number;
Could the declaration of the integer some_number be legally written like this? :
int some_number = 'A' * 'a' + 'Z' * 'z';

The number 1 appears all along the top row and down the left-side column. Each of the other numbers is formed by adding the number directly above it to the one directly to its left. Write a program using a two dimensional array which calculates Pascal's triangle. I will leave you to decide how many rows and columns it should have.
Now adapt the program so that it encodes the numbers in some way, for instance, adding 5 on to each of the ASCII values and displaying the character represented by the resulting value. You will need to write a program to accompany this first one that "decodes" the message in a similar way.
int x = 2, y = 3; // ?
if (x <= y)
{ float x = 2.7, y = 6.4; // ?
int z = 10;
do // ?
{ int x = 30; // ?
cout << x + y + z << endl;
x--;
z++;
}
while (z < 40);
// ?
}
Now use your program to investigate the following conundrum:
Try this procedure on several three digit numbers. What do you notice about your answers?
When it is the player's turn to go, two grids are displayed side by side. The first shows the positions of the bombs dropped by the player on the computer's navy, indicating whether they have hit anything or not. The second, shows the state of the player's navy - ships that are intact, ships that have been sunk and bombs dropped by the computer that have missed their targets.
A typical screen might look like this:
|
8 |
. |
. |
. |
. |
. |
. |
. |
. |
8 |
. |
. |
. |
M |
. |
. |
. |
. |
|
|
7 |
. |
. |
. |
. |
. |
M |
. |
. |
7 |
. |
M |
. |
. |
. |
H |
. |
. |
|
|
6 |
. |
. |
H |
. |
. |
. |
. |
. |
6 |
. |
. |
S |
. |
. |
. |
. |
. |
|
|
5 |
. |
. |
. |
. |
. |
. |
. |
. |
5 |
. |
. |
. |
. |
. |
. |
. |
M |
|
|
4 |
. |
. |
. |
. |
. |
M |
. |
. |
4 |
. |
. |
. |
. |
. |
S |
. |
. |
|
|
3 |
. |
. |
. |
. |
M |
. |
. |
. |
3 |
S |
. |
. |
. |
. |
. |
. |
. |
|
|
2 |
. |
. |
. |
. |
. |
. |
. |
. |
2 |
. |
. |
. |
S |
S |
. |
. |
. |
|
|
1 |
. |
. |
. |
. |
. |
. |
. |
. |
1 |
. |
. |
. |
. |
. |
. |
. |
. |
|
|
A |
B |
C |
D |
E |
F |
G |
H |
A |
B |
C |
D |
E |
F |
G |
H |
|||
A letter H represents a bomb that hit something, M represents a bomb that missed and S represents one of the player's ships.
Then write a function that chooses a random position for each of the ships. This will involve choosing a random horizontal position (in the range 0 to 7) and a random vertical position (also in the range 0 to 7). For each position, set the appropriate element of the grid that holds the positions of the computer's ships to 1 (or some predefined constant value called SHIP).
Your function will have to prevent the computer from choosing the same position for more than one ship, which is a distinct possibility if they are being chosen at random. This is done by including a loop within the main loop (going through all the different ships) that checks the position chosen to see whether it contains the value 0 (empty) or SHIP. The position is only accepted if it is empty.
The program should also ensure that the positions chosen for the ships are all different. This can be done in a similar way to the routine in Task 2 - re-prompt the user if he/she tries to sneak two ships into the same square.
When displaying the computer's grid, make sure you don't display the positions of the intact ships - that would make the game a bit too easy! Display these elements using the same character as used for empty sea. You will need to pass a parameter to the function that indicates whether it is the player's grid that is being displayed or the computer's.
As well as the contents of the grids you should display the letters A to H along the bottom of the grid and the digits 0 to 7 (or 1 to 8) up the side.
Either way, the result of the bombing should be displayed using an appropriate message ("You missed, you pansy!" or "Ouch! That hit me amidships!" or something similar). The next time the computer's grid is displayed that square should appear as H or M (or similar).
The result of the bombing presents a small problem. Should you get the computer to check the player's grid and report "Yippee! I've hit a ship" or ask the player to type in whether a ship has been hit? The former is certainly easier to program, but the player may think that the computer has cheated and looked at the grid. I will leave you to thrash this one out!
The functions that you have written should make good use of local variables. Since each one was written in isolation, it makes sense to include the variable declarations within the functions itself. Many programmers stick to similar names for variables that have certain functions. For instance, loop counters are often called i, j, k etc. Using local variables allows the programmer to call the first loop counter in every function i if desired.
Now that you know how to store things in two-dimensional grids, you can use it to represent things like chess boards, simple maps etc.
For instance, you might like to include a two-player option, whereby two human opponents play against each other using the computer to store, display and keep track of the moves. One obvious problem presents itself - how do you stop the two opponent's looking at each others' boards. One possible way is to display a message when it's the end of each player's turn to the effect that they must leave the computer now. This could be backed up by asking them to enter a secret character (perhaps a letter of the alphabet or punctuation symbol) chosen by the player at the start of the game, which would then blank the screen (done by writing a large number of blank lines so that the grid disappeared off the top of the screen). Even so, there is a degree of trust involved.
At the moment, each ship just occupies one square, and a lucky hit from a bomb destroys the ship instantly. In proper versions of Battleships, there are different kinds of ships - submarines occupying one square, cruisers occupying two neighbouring squares, frigates taking up three etc. - which adds a degree of skill to the game. Having been told "You've hit a cruiser", the player would then use successive shots to find the rest of the ship in the adjacent squares in order to sink it. This makes placing the ships more complicated, both for the program as well as the human player, as these multi-square ships can be placed across the board or down it.
This sort of game would benefit immensely from the use of computer graphics. However, standard C++ does not include graphical commands (although there are many versions of C++ which do), so they are outside the scope of this book. Feel free to replace any of the letter codes on the screen with still or animated images.

Well, you don't. However, it doesn't really matter. The program doesn't worry about how you interpret the array when it stores it in memory. For instance, this program segment…
for (int x = 0; x < 5; x++)
{ for (int y = 0; y < 5; y++)
cout << m[x][y];
cout << endl;
}
might display array values as follows:
35 20 11 0 100
-89 17 99 21 31
29 63 61 40 12
39 63 89 300 -14
-2 807 210 45 -300
Changing the cout instruction to cout << m[y][x]; would turn the rows into columns and vice-versa:
35 -89 29 39 -2
20 17 63 63 807
11 99 61 89 210
0 21 40 300 45
100 31 12 -14 -300
Note the use of the cout << endl; instruction to separate the lines of the array. This instruction is present in the outer loop but is not part of the inner loop.

Of course, you will want to put an upper limit on the random number (e.g. in the range 0 to 120 or whatever). This is done by applying the modulo operator to the random number produced, and finding the remainder when divided by your upper limit. This explains why the number produced is always in the range 0 to one less than the limit you specify - the remainder cannot be the limit number itself (e.g. if you divide by 6, the remainder can't be 6).
You can experiment with the following pseudo-random number generator. How "random" are the numbers? What happens when you try to get very large random numbers?
long seed = 123456; // Try different starting values
const long prime1 = 60013;
const long prime2 = 60017;
long rand (long limit)
{ seed = (seed + prime1) / prime2;
// Integer division, remember!
return seed % limit;
}
Why doesn't the variable seed have the word const next to it?

Sorry! It's not possible, unlike some languages (like Pascal) the lowest index of an array is always 0. Of course, you don't have to use all those elements. If you are only interested in elements 20 to 30, then declare an array with 31 elements (top index 30) and ignore the elements 0 to 19.
It gets a little harder if you want negative indices. Suppose you want an array where the indices go from -2 to +2. In this case, before you store the values in the array, add 2 to the index:
int n[5]; // The indices are 0 to 4
int index = -2; // We want to pretend that the
// indices start at -2
n[index+2] = 30; // The closest we will get to n[-2]

const days_in_months[] = {0, 31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31};
This array holds the number of days in each month of the year. I have decided to include a 0 as the first element so that the real values start with index 1. I personally don't like counting array indices from 0 - I prefer counting from 1, and as a result, I am prepared to waste one array element.