Lycos Search
 Search: The Web Tripod
iconReport Abuse      « Previous | Top 100 | Next » logo
  angle graphic
Select Rating(514)
share: del.icio.us | digg | reddit | furl | facebook

Project 4 - Battleships!

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.

Aspects of C++ covered

Arrays

Up to now we have only considered simple variables which contain one value. Arrays offer a way to store several (many) variables together under one name. Think of an array as a series of pigeon holes, each with its own number:

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].

Listing 4.1

#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:

Listing 4.2

#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.

Two dimensional arrays

These are rectangular grids of numbers. Here you have two dimensions, and each is referred to by its own index number in square brackets [like][this].

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:

Listing 4.3

#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];

Passing arrays as function parameters

This is done in a similar fashion to ordinary variables. In the function definition, the parameter name (which needn't match the name of the array in the main program, of course) must have square brackets after it to denote it is an array:

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

Initialising arrays during declaration

You already know that ordinary variables can be initialised while they are being declared, as follows:

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.

Including Standard Header Files - Pseudo-random numbers

C++ contains the facility to generate random numbers, which can be used in games, scientific simulations etc. However, the numbers aren't really random, they are numbers generated from a formula, so that each number is related to the previous and the next one. However, the formula is so complicated that, to all extents and purposes, they can be thought of as random.

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:

Listing 4.4

#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.

Variable scope

All the variables that we have used so far have been global, meaning that they could be used anywhere in the program. This is because they have been declared near the start of the program just after the #include statement(s). It is however possible to declare variables that pop into and out of existence, so-called local variables. We say that these variables have limited scope - they can only be used in certain parts of the program. The scope of the variable simply means its lifetime - the part of the program between where it comes into existence and where it disappears.

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().

Implicit conversion of characters to numbers

Computer memory is only really capable of storing numbers, and anything else in a program, such as characters, symbols or pieces of text, have to be boiled down to a series of numbers before they can be stored. You can refer to the characters in their raw numerical form by setting an integer variable equal to a character one, for instance:

Listing 4.5

#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:

Listing 4.6

#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.

Exercises

  1. Write a program that carries out the following tasks: It sets up a single-dimension array of 100 numbers. It then asks the user for two numbers, a starting value and a difference. The starting value is copied into the first array element and each of the following elements is the previous one plus the difference (e.g. if the starting value were 7.5 and the difference were 2.5, then the array would contain 7.5, 10, 12.5, 15 etc.) Finally, the program displays the final value in the array.

  2. This is a variation on the previous exercise. It is a procedure for finding prime numbers, called the "Sieve of Eratosthenes" after the Greek mathematician who first formulated it. Prime numbers are whole numbers which can only be divided by 1 and themselves (so 17 is a prime number as the only whole numbers that go into it are 1 and 17). The number 1 does not count as a prime number.

    1. Declare a single-dimensional array containing 200 numbers, starting at 2 (not 1 or 0 - these are not prime numbers).
    2. Display on the screen the first number in the array that isn't zero (this will be 2 to start with).
    3. Set that number to 0 and go through the array setting all multiples of that number to 0 (e.g. if it is 2 you are considering, set the array elements to 0 that contain 2, 4, 6, 8 etc.)
    4. If there are non-zero numbers in the array, choose the next non-zero number in the array (e.g. if you have been wiping out multiples of 2, then the next number to consider will be 3) and go back to step 2.
    5. When all the array has been reduced to zeros, the screen will show all the prime numbers up to 200.

    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.

  3. Given that the ASCII value of the character 'A' is 65 and the ASCII value of the character 'a' is 97, what number would be displayed by the following code segment?

    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';

  4. This diagram shows a series of numbers called Pascal's triangle. These are normally written in a triangular form with the number 1 at the top, but I have rewritten them to make them look more "rectangular".

    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.

  5. Write a program that asks the user to enter a message, one character at a time, and then displays the message as a series of ASCII values. You can either store the message in an array of characters and then display all the numbers at the end, or display each number as the message is entered.

    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.

  6. Scan through the following code segment to determine which variables exist at which points. Then expand the code segment to form a propert program and add cout statements to display the values of the variables at each point marked with a question mark in the segment. Does the resulting output match up with your predictions?

    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);
           // ?
        }
    

  7. Write a program that asks you to enter a three digit number and then splits it into its separate digits in three separate character variables. It would turn the number 283 into the characters "2", "8" and "3".

    Now use your program to investigate the following conundrum:

    1. Think of any three digit number where the first and last digits are different.
    2. Reverse the number. Subtract the smaller three-digit number from the larger one (so, if you started with 283, you would get 382 - 283 = 99.
    3. Now reverse the answer. You may need to put a 0 on the front to make it three digits long, so 99 becomes 099, which reverses to give 990.
    4. Add the numbers that you got in parts (3) and (4) together.

    Try this procedure on several three digit numbers. What do you notice about your answers?

The Project Itself

The version of the game that we are going to construct will let the user play against the computer. Both the computer's grid of ships and the player's will be stored inside the program. This does mean that the player will have to trust the program not to take a sneaky peek at where he/she has placed the ships - you might like to include a message in the program to the effect that the computer can be relied upon not to cheat!

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:

Your bombs:
Your navy:

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.

Task 1

The heart of the program will be the two grids. These will need to be declared as being 8-by-8 grids (i.e. the array indices will go from 0 to 7 in both directions). You will also need to write a function that fills both these arrays with zeros. You might think that they could be initialised to 0 during declaration, which would be fine if you were sure that the player only wanted one game. However, later you are going to add a "Do you want another game?" loop, so the arrays will need to be re-initialised to zero.

Task 2

The next task is to write a function that lets the computer choose the random positions of it ships. Firstly, set up a constant value, called NUM_SHIPS or similar, that defines how many ships there will be. Where should this constant be declared? Should it be within the function that chooses the random positions, within the function main() or at the top of the program?

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.

Task 3

Now you have to get the user to enter his/her ship positions. For each ship, the user will have to enter a letter (the horizontal position) and a number (the vertical position). The letter, in the range 'A' to 'H', will have to be converted to a number, in the range 0 to 7. This is fairly easy to do, bearing in mind that characters are stored as numbers in memory anyway. You can decide whether the user has to enter a number in the range 1 to 8 or in the range 0 to 7. If you decide on 1 to 8, then a small amount of conversion will be needed to store the ships in the array.

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.

Task 4

Write a function that will display either one of the two grids on the screen. The appropriate array is passed as a parameter and a switch statement used to display an appropriate character for element of that array (I suggest S for a ship, H for a ship that has been hit - and sunk! - M for a bomb that has missed etc.)

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.

Task 5

Now things get violent! Write a function which asks the player to choose a position where a bomb is to be dropped. You can reuse code that you developed in Task 3 for choosing positions. If you like, you can prevent the player from choosing a square that has already been chosen (although this isn't too important - if the player is stupid enough to drop two bombs in the same place, it's too bad!)

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).

Task 6

This is where the computer gets its revenge! Write a function that chooses a random position on the player's grid and drops a bomb on it. You should ensure that the computer does not choose a location which it has chosen before. The computer displays its move on the screen with an appropriate message.

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!

Task 7

Write a function that takes an array as a parameter (either the player's grid or the computer's) and determines whether it contains any ships that are still afloat. It should return a value 1 if the navy is still (partly) afloat, or 0 otherwise.

Task 8

Now you have all the component parts to put the game together. The only extra items that you need are a loop to allow both sides to drop as many bomb as it takes, and a few statements to report who's won. Happy battling!

Discussion

You will have written several functions for this project, and in the later stage stitched them together to form a working program. This sort of approach is usually referred to as bottom-up. In the computing industry, programs are often written in this manner, with different parts being "farmed out" to different teams, and then put together at a later stage. Of course, testing the functions can prove rather difficult as a skeleton program has to be written round each one in order for it to run. The alternative approach is top-down, where large tasks are continually broken down into smaller, more manageable chunks.

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.

Extensions

The version of Battleships that we have constructed here is a simple one. There are several improvements that can be made, although each requires a fair amount of planning, and a great deal of work!

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.

Questions and Answers

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.

This will depend on your implementation of C++, but it is likely to use a routine similar to the following. It takes the seed number, adds a large prime number to it, and then takes the remainder when it is divided by another large prime number. This produces the next random number in the sequence, and the next seed.

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]

Yes, no problem! Just put the word const in front of the array name when it is declared. This only really makes sense when the array is initialised with values:

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.

Summary


Site Sponsors
sponsor logo sponsor logo sponsor logo WIRED