Battleship game

I need some help with my battleship game.
I'm running into errors I have the majority of it written but the issues I am having are in the main. Putting all the pieces together is where I'm having trouble. I have some run time check failures (these are tagged with comments in the code). And need help with working out the hits and sinks. Any help would be appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <conio.h>
#include <sstream>

using namespace std;


//Below is an enumerated data type so that I can use the labels 'VERTICAL', and 'HORIZONTAL' to designate the
//direction of a ship.
enum ShipDirection {VERTICAL, HORIZONTAL};

//This is the ship class, it is a blue print for a ship.
//The game of battleship utilizes 5 ships of various sizes. 
class Ship
{
	private:

		int numOfHits;
		ShipDirection shipDir;
		int startRow;
		int startCol;
		string shipType;

	public:
		
		Ship()
		{
			shipType = "";
			shipDir = VERTICAL;
			startRow = 0;
			startCol = 0;
			numOfHits = 0;
		}
		 
		Ship(int nHits, string name)
		{
			shipType = name;
			shipDir = VERTICAL;
			startRow = 0;
			startCol = 0;
			numOfHits = nHits;
		}


		//Created sets and gets for all of the data members in the private: section of this class.
		void setStartRow(int sR)
		{
			startRow = sR;
		}

		int getStartRow()
		{
			return startRow;
		}

		void setStartCol(int sC)
		{
			startCol = sC;
		}

		int getStartCol()
		{
			return startCol;
		}

		int getNumberOfHits()
		{
			return numOfHits;
		}

		ShipDirection getShipDir()
		{
			return shipDir;
		}

		void setShipDir(ShipDirection sD)
		{
			shipDir = sD;
		}

		string getNameOfShip()
		{
			return shipType;
		}

		void setNameOfShip(string nOS)
		{
			shipType = nOS;
		}
};



//This is the board class. This class represents the board. The board class contains a 2 dimensional array.
//That array is filled with zeros initially. If there is a ship at a certain coordinate at that array, it will contain a 
//'1', if there is a space of a ship that has been hit at a certain coordinate of the board array, it will contain a '2'.

class Board
{
	private:
		int board[10][10];

	public:
		Board()
		{
			for (int row = 0; row < 10; row++)
			{
				for (int col = 0; col<10; col++)
				{
					board[row][col] = 0;
				}
			}
		}
		
		//This function places a ship on the board 
		void placeShip(Ship ship)
		{
			//Create a random number between 0 and 1 to represent the direction of the ship
			int sD = rand()%2;
			int sR = rand()%10;
			int sC = rand()%10;

			if (sD==0)
			{
				ship.setShipDir(VERTICAL);
			}
			else 
			{
				ship.setShipDir(HORIZONTAL);
			}
			
			while(!isClearSpace(sR, sC, ship.getNumberOfHits(), ship.getShipDir()))
			{
				sR = rand()%10;
				sC = rand()%10;
			}

			ship.setStartRow(sR);
			ship.setStartCol(sC);
			setShip(sR, sC,ship.getNumberOfHits(),ship.getShipDir());		
		}
 
		bool isClearSpace(int startRow, int startCol, int size, ShipDirection shipDir)
		{
			if(shipDir == VERTICAL)
			{
				if(startRow + size > 9)
				{
					return false;
				}
				for(int row = startRow; row < startRow+size; row++)
				{
					if(board[row][startCol] !=0)
					{
						return false;
					}
				}
			}
			else if(shipDir==HORIZONTAL)
			{
					if(startCol + size > 9)
				{
					return false;
				}
					for(int col = startCol; col < startCol+size; col++)
				{
					if(board[startRow][col] !=0)
					{
						return false;
					}
				}
			}
			return true;
		}		

		void setShip(int startRow, int startCol, int size, ShipDirection shipDir)
		{
			if(shipDir == VERTICAL)
			{
				for(int row = startRow; row < startRow+size; row++)
				{
					board[row][startCol] = 1;
				}
			}
			else if(shipDir==HORIZONTAL)
			{
					for(int col = startCol; col < startCol+size; col++)
				{
					board[startRow][col] = 1;
					
				}
			}
		}	
		

		
		//Print board 
		void printBoard()
		{
			cout << "  0 1 2 3 4 5 6 7 8 9" << endl;
			char rowLabel = 'A';
			for(int row = 0; row < 10; row++)
			{
				cout << rowLabel << " ";
				rowLabel++;
				for(int col = 0; col < 10; col++)
				{
					cout << board[row][col] << " ";
				}
				cout << endl;
			}
		}

		
		
		//This takes in a row and a col
		//it then checks to see if the guess is a hit or not
		//if there is not a zero at that place it has to be 
		//a 1 or a 2, I will consider that to be a hit
		//my version of the game does not take into account
		//whether the user hits the boat at the same place
		//more then once
		bool isHit(int row, int col)
		{
			if(board[row][col] != '1')
			{
				board[row][col] = '2';
				return true;
			}
			
			if(board[row][col] = '0')
			{
				return false;
			}
			
		}

		//Checks the entire board 
		//if there are any 1's there is boat still on the board that is not yet hit
		//so return false if it finds a 1, otherwise the game is over
		bool isGameWon()
		{
			for(int row = 0; row < 10; row++)
				for(int col = 0; col < 10; col++)
					if(board[row][col] = 1)
					{   
					return false; //game is not yet won
					}
				

			return true; 
			
		}

		//Checks to see if this particular ship is sunk by checking to see
		//if the board at this ship's position is all 2s.
		bool isShipSunk(Ship ship, int startRow, int startCol, int size, ShipDirection shipDir)
		{
			if(shipDir == VERTICAL) 
			{
				if(startRow + size > 9)  
				{
					return false;
				}
				for(int row = startRow; row < startRow+size; row++)
				{
					if(board[row][startCol] !='2')
					{
						return false;
					}
				}
			}
			else if(shipDir==HORIZONTAL)
			{
					if(startCol + size > 9) 
				{
					return false;
				}
					for(int col = startCol; col < startCol+size; col++)
				{
					if(board[startRow][col] !='2')
					{
						return false;
					}
				}
			}
			return true;
		}

		
};





int _tmain(int argc, _TCHAR* argv[])
{
	
	//Seed the random number generator with the current time
	srand(time(0));

	char guessRow;
	int guessCol;
	char playAgain();
	char keepPlaying;
	bool isGameWon;
	bool isHit;
	//While the player intends to keep playing
	do
		{
		//Create each of the five ships
		Ship carrier = Ship(5, "Carrier");
		Ship battleship = Ship(4, "Battleship");
		Ship submarine = Ship(3, "Submarine");
		Ship destroyer = Ship(3, "Destroyer");
		Ship patrolboat = Ship(2, "Patrol boat");
		
		

		//Create the board
		Board board = Board();
                //place ships on board
		board.placeShip(carrier);
		board.placeShip(battleship);
		board.placeShip(submarine);
		board.placeShip(destroyer);
		board.placeShip(patrolboat);

		//print the board with the ships on it temporarily for testing, when the game is finished I will take this out.
		board.printBoard();

		
		
			do
			{
			//Asks User for Coordinates of their choice.
	        cout << "\n\nPlease enter your coordinates: \n";
			cout << "Enter row: ";  
			cin >> guessRow;
	        guessRow = toupper(guessRow);
			cout << "Enter column: ";
	        cin >> guessCol;
			cout << endl;
		    
		        
			if (isHit != false)//"Run-Time Check Failure #3 - The variable 'isHit' is being used without being initialized."
			{
				cout << "Its a hit \n"; 
			}
			
	//check each ship to see if it was sunk.
			//Need help here to to work out hits with sinks
		/*if(board.isShipSunk(carrier))
		{ cout << "You sunk my Carrier!"; } 
		
		if(board.isShipSunk(battleship))
		{ cout << "You sunk my Battleship!"; } 

		if(board.isShipSunk(submarine))
		{ cout << "You sunk my Submarine!"; } 

		if(board.isShipSunk(destroyer))
		{ cout << "You sunk my Destroyer!"; } 

		if(board.isShipSunk(patrolboat))
		{ cout << "You sunk my Partrol boat!"; }*/ 
		//do that on all 5 ships
		    
		else 
			{
				cout << "It was a miss! \n";
			}

	
		

		}
		while (isGameWon != true );//"Run-Time Check Failure #3 - The variable 'isGameWon' is being used without being initialized."
	
	
	

	//ask the player if he or she intends to keep playing
		keepPlaying = playAgain();
		if ( keepPlaying == 'N')
		{
			cout << "Goodbye \n";
			system("pause");
			return 0;
		}
	}
	while (keepPlaying == 'Y');
	
}

//play again
char playAgain()
{
	char keepPlaying;
	cout << "Would you like to play again? (y or n) ";
	do
	{
		cin >> keepPlaying;
		keepPlaying = toupper(keepPlaying);
		if (keepPlaying!='Y' && keepPlaying != 'N')
			cout << "Enter only a 'Y' or an 'N', please!" << endl << endl;
	} while ( keepPlaying !='Y' && keepPlaying != 'N'); 
	return keepPlaying;
}
Sorry, I haven't understood your game board.
Can you explain more :
- Unit (position)
- Columns, Rows
- Events

Hope this helps
Ok the unit(position) are randomly generated in either a vertical or horizontal position then randomly generated to fill in the space of different unit ( ie carrier is 5 spaces) as long as the space is clear there is no overlapping of ships and ships stay on the board.

The grid rows/columns looks like this:
0 1 2 3 4 5 6 7 8 9 10
A 0 0 0 0 0 0 0 0 0 0
B 0 0 0 0 0 0 0 0 0 0
C 0 0 0 0 0 0 0 0 0 0
D 0 0 0 0 0 0 0 0 0 0
E 0 0 0 0 0 0 0 0 0 0
F 0 0 0 0 0 0 0 0 0 0
G 0 0 0 0 0 0 0 0 0 0
H 0 0 0 0 0 0 0 0 0 0
I 0 0 0 0 0 0 0 0 0 0
J 0 0 0 0 0 0 0 0 0 0

With ships loaded it looks like this

0 1 2 3 4 5 6 7 8 9 10
A 0 0 0 0 0 0 0 0 0 0
B 0 0 0 1 0 0 0 0 1 1
C 0 0 0 1 0 0 0 0 0 0
D 0 0 0 1 0 0 0 0 0 0
E 0 0 0 1 0 0 0 0 0 0
F 0 0 0 1 0 0 0 0 0 0
G 0 0 0 0 0 0 0 0 0 0
H 1 1 1 0 0 0 0 1 1 1
I 0 0 0 0 0 0 0 0 0 0
J 0 1 1 1 1 0 0 0 0 0

Events are
user enters a row and column that if it corresponds to a ship location that ship gets a hit the 1 turns to a 2, if all the hits for a ship are hit that ship is sunk. If all the ships are sunk the game is over and the user has the option to play again.

The issues I am having are in the main basically putting it all together.
"Run-Time Check Failure #3 - The variable 'isHit' is being used without being initialized."
And
"Run-Time Check Failure #3 - The variable 'isGameWon' is being used without being initialized."
Are the main issues I'm having then I need help working out the hits to sinks.

Does this answer your questions?
Try initiating the variable 'isHit' and 'isGameWon', then try again.

isHit = false;
isGameWon = false;
The problem is exactly what Run-Time Check Failures say they are. You are declaring two bool variables, isHit and isGameWon. But nowhere in your code does anything assign a value to those variables.

You've also defined some methods, Board::isHit() and Board::isGameWon(). I think you probably meant to call those functions and check their return values, instead of checking the value of a bool variable with same name.

Edit: And be wary of any advice from Jackson Marie. He/she is occasionally right, but often posts terrible advice.
Last edited on
@MikeyBoy
Yes I want to call those functions and check their return value. How would I go about doing that?
Would I set a "=false" to the declared variables as Jackson Marie suggests or is there a different way to do it? I have been searching Google but can't pin it down.
Thanks for your help here.
Are those warnings?
Did you set your project "warning level 4"?
Last edited on
Yes I want to call those functions and check their return value. How would I go about doing that?
Would I set a "=false" to the declared variables as Jackson Marie suggests or is there a different way to do it? I have been searching Google but can't pin it down.
Thanks for your help here.

No, Jackson Marie's comments in this thread are irrelevant to your problem.

I'm not sure why you're confused about how to call a method and check it's return value, since you do it perfectly fine in several other places in your code, e.g. at line 134. Just do the same thing to call the isHit and isGameWon methods.

Calling a function/method is one of the most basic elements of programming. If you're not sure how to do it, you really need to be going back to your introductory texts and getting those concepts clear in your mind.

I'd also very strongly recommend against defining variables and functions with the same name. Your code will be easier to understand, and therefore easier to fix when it goes wrong.
Last edited on
Ok I sat down and worked out some of the issues with the code I got the isHit working and coded the sunk ships. However, now I have a new issues once I sink a ship and start attacking another ship it prints out"

(if I already sunk the patrol boat, and start on the battleship)
"Its a hit."
you sunk my patrol boat!"

Then if I sink the battleship it prints out
"Its a hit"
"You sunk my battleship! You sunk my patrol boat!"

Then once all the ships are sunk. The game should ask if the user wants to play again, but it keeps asking for coordinates. I think the issue is in isHit function that should change the 1's to 2's but doesn't.

Here is the updated code from the isHit function down.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//This takes in a row and a col
		//it then checks to see if the guess is a hit or not
		//if there is not a zero at that place it has to be 
		//a 1 or a 2, I will consider that to be a hit
		//my version of the game does not take into account
		//whether the user hits the boat at the same place
		//more then once
		bool isHit(int row, int col)
		{
			if(board[row][col] = 1)
			{
				board[row][col] = 2;
				return true;
			}
			
			else
			{
				return false;
			}
			
		}

		//Checks the entire board 
		//if there are any 1's there is boat still on the board that is not yet hit
		//so return false if it finds a 1, otherwise the game is over
		bool isGameWon()
		{
			for(int row = 0; row < 10; row++)
				for(int col = 0; col < 10; col++)
					if(board[row][col] = 1)
					{   
					return false; //game is not yet won
					}
				

			return true; 
			
		}

		//Checks to see if this particular ship is sunk by checking to see
		//if the board at this ship's position is all 2s.
		bool isShipSunk(Ship ship, int startRow, int startCol, int size, ShipDirection shipDir)
		{
			if(shipDir == VERTICAL) 
			{
				if(startRow + size > 10)  
				{
					return false;
				}
				for(int row = startRow; row < startRow+size; row++)
				{
					if(board[row][startCol] !=2)
					{
						return false;
					}
				}
			}
			else if(shipDir==HORIZONTAL)
			{
					if(startCol + size > 10) 
				{
					return false;
				}
					for(int col = startCol; col < startCol+size; col++)
				{
					if(board[startRow][col] !=2)
					{
						return false;
					}
				}
			}
			return true;
		}
};


int _tmain(int argc, _TCHAR* argv[])
{
	
	//Seed the random number generator with the current time
	srand((unsigned int) time(0));

	char guessRow;
	int guessCol;
	char playAgain();
	char keepPlaying;
	bool isGameWon;
	bool isHit;
	//While the player intends to keep playing
	do
		{
		//Create each of the five ships
		Ship carrier = Ship(5, "Carrier");
		Ship battleship = Ship(4, "Battleship");
		Ship submarine = Ship(3, "Submarine");
		Ship destroyer = Ship(3, "Destroyer");
		Ship patrolboat = Ship(2, "Patrol boat");
		
		

		//Create the board
		Board board = Board();

		//Place the ships on the board 

		board.placeShip(carrier);
		board.placeShip(battleship);
		board.placeShip(submarine);
		board.placeShip(destroyer);
		board.placeShip(patrolboat);
		//print the board with the ships on it temporarilly for testing, when the game is finished I will take this out.
		board.printBoard();

		
		
			do
			{
			//Asks User for Coordinates of their choice.
	        cout << "\n\nPlease enter your coordinates: \n";
			cout << "Enter row: ";  
			cin >> guessRow;
	        guessRow = toupper(guessRow);
			cout << "Enter column: ";
	        cin >> guessCol;
			cout << endl;
			isHit=board.isHit(guessRow-'A',guessCol);
		        
			if (isHit)
			{
				cout << "Its a hit \n"; 
			}
			else 
			{
				cout << "It was a miss! \n";
			}
			//check each ship to see if it was sunk.
			
			
			if(board.isShipSunk(carrier,carrier.getStartRow(),carrier.getStartCol(),carrier.getNumberOfHits(),carrier.getShipDir()))
			{ cout << "You sunk my Carrier!"; } 
		
			if(board.isShipSunk(battleship,battleship.getStartRow(),battleship.getStartCol(),battleship.getNumberOfHits(),battleship.getShipDir()))
			{ cout << "You sunk my Battleship!"; } 

			if(board.isShipSunk(submarine,submarine.getStartRow(),submarine.getStartCol(),submarine.getNumberOfHits(),submarine.getShipDir()))
			{ cout << "You sunk my Submarine!"; } 

			if(board.isShipSunk(destroyer,destroyer.getStartRow(),destroyer.getStartCol(),destroyer.getNumberOfHits(),destroyer.getShipDir()))
			{ cout << "You sunk my Destroyer!"; } 

			if(board.isShipSunk(patrolboat,patrolboat.getStartRow(),patrolboat.getStartCol(),patrolboat.getNumberOfHits(),patrolboat.getShipDir()))
			{ cout << "You sunk my Partrol boat!"; }
			//do that on all 5 ships	

			isGameWon=board.isGameWon();
		
			
		}
		while (!isGameWon);
	

	//ask the player if he or she intends to keep playing
		keepPlaying = playAgain();
		if ( keepPlaying == 'N')
		{
			cout << "Goodbye \n";
			system("pause");
			return 0;
		}
	}
	while (keepPlaying == 'Y');
	
}

//play again
char playAgain()
{
	char keepPlaying;
	cout << "Would you like to play again? (y or n) ";
	do
	{
		cin >> keepPlaying;
		keepPlaying = toupper(keepPlaying);
		if (keepPlaying!='Y' && keepPlaying != 'N')
			cout << "Enter only a 'Y' or an 'N', please!" << endl << endl;
	} while ( keepPlaying !='Y' && keepPlaying != 'N'); 
	return keepPlaying;
}
The best way to diagnose problems like this is with a debugger. That way, you can break the program at points in its execution, and see exactly what the values of different variables are, and see exactly which decisions it's making and which lines of code it's executing.

As it happens, I've spotted what's wrong. In the if statement in isGameWon(), you're not comparing board[row][col] to 1. You're setting it to 1. And then, since the expression board[row][col] = 1 evaluates to 1, that if statement is true, and the method returns false.

The equality comparison operator in C and C++ is ==. A single = assigns a value to a variable.

You're also doing the same thing in isHit().

This is such a common mistake, and such a potentially tricky one to spot, that most modern compilers will give a warning if it's happening in your code. Did your compiler not warn you about it?
Thanks for your help MikeyBoy. I have actually moved past this issue and cleaned up the out put so that at the top of the screen it displays the Ship Status either "At large" or "Sunk".
This is one of the biggest programs I have written to date and I think the scope of it is throwing me for loop or two.
My current issue (maybe you can help me clear up this one last issue) before I submit the code?

With ships loaded on the board the output looks like this.


0 1 2 3 4 5 6 7 8 9 10
A 0 0 0 0 0 0 0 0 0 0
B 0 0 0 1 0 0 0 0 1 1
C 0 0 0 1 0 0 0 0 0 0
D 0 0 0 1 0 0 0 0 0 0
E 0 0 0 1 0 0 0 0 0 0
F 0 0 0 1 0 0 0 0 0 0
G 0 0 0 0 0 0 0 0 0 0
H 1 1 1 0 0 0 0 1 1 1
I 0 0 0 0 0 0 0 0 0 0
J 0 1 1 1 1 0 0 0 0 0


Not much sport seeing the ships and being able to sink them with little to no effort. Here is the print board statement. How can I modify this to to display all '0' instead of 1's where the ships are, basically making the ships invisible and the game more challenging?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Print board 
		void printBoard()
		{
			cout << "  0 1 2 3 4 5 6 7 8 9" << endl;
			char rowLabel = 'A';
			for(int row = 0; row < 10; row++)
			{
				cout << rowLabel << " ";
				rowLabel++;
				for(int col = 0; col < 10; col++)
				{
					cout << board[row][col] << " ";
				}
				cout << endl;
			}
		}
Topic archived. No new replies allowed.