-
Notifications
You must be signed in to change notification settings - Fork 0
/
battleships.c
401 lines (338 loc) · 12.5 KB
/
battleships.c
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
/* ENGGEN131 C Project 2023 - Battleships */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAP_SIZE 6
#define HIT 1000
// Prototype declarations of required functions
void PrintArray(int values[MAP_SIZE][MAP_SIZE]);
void InitialiseMap(int map[MAP_SIZE][MAP_SIZE]);
void AddRandomShip(int size, int map[MAP_SIZE][MAP_SIZE]);
int CountValues(int value, int map[MAP_SIZE][MAP_SIZE]);
int TopLeftPosition(int size, int *row, int *col, int map[MAP_SIZE][MAP_SIZE]);
int IsShipValid(int size, int map[MAP_SIZE][MAP_SIZE]);
void InitialiseRandomMap(int map[MAP_SIZE][MAP_SIZE]);
void FireShot(int shots[MAP_SIZE][MAP_SIZE], int map[MAP_SIZE][MAP_SIZE], int row, int col);
int CheckGameOver(int shots[MAP_SIZE][MAP_SIZE], int map[MAP_SIZE][MAP_SIZE]);
/******************************************************************************
*******************************************************************************
*******************************************************************************
// Implementations of the required functions should go below
*******************************************************************************
*******************************************************************************
******************************************************************************/
void PrintArray(int values[MAP_SIZE][MAP_SIZE])
{
values[0][0] = 0; // to prevent compiler warning (you must complete this function)
}
void InitialiseMap(int map[MAP_SIZE][MAP_SIZE])
{
map[0][0] = 0; // to prevent compiler warning (you must complete this function)
}
void AddRandomShip(int size, int map[MAP_SIZE][MAP_SIZE])
{
map[0][0] = size; // to prevent compiler warning (you must complete this function)
}
int CountValues(int value, int map[MAP_SIZE][MAP_SIZE])
{
return map[0][0] + value; // to prevent compiler warning (you must complete this function)
}
int TopLeftPosition(int size, int *row, int *col, int map[MAP_SIZE][MAP_SIZE])
{
return map[0][0] + size + *row + *col; // to prevent compiler warning (you must complete this function)
}
int IsShipValid(int size, int map[MAP_SIZE][MAP_SIZE])
{
return map[0][0] + size; // to prevent compiler warning (you must complete this function)
}
void InitialiseRandomMap(int map[MAP_SIZE][MAP_SIZE])
{
map[0][0] = 0; // to prevent compiler warning (you must complete this function)
}
void FireShot(int shots[MAP_SIZE][MAP_SIZE], int map[MAP_SIZE][MAP_SIZE], int row, int col)
{
shots[0][0] = map[0][0] + row + col; // to prevent compiler warning (you must complete this function)
}
int CheckGameOver(int shots[MAP_SIZE][MAP_SIZE], int map[MAP_SIZE][MAP_SIZE])
{
return shots[0][0] + map[0][0]; // to prevent compiler warning (you must complete this function)
}
/******************************************************************************
*******************************************************************************
*******************************************************************************
// Implementations of the required functions should go above
*******************************************************************************
*******************************************************************************
******************************************************************************/
// Provided functions needed for playing the Battleships game:
// First, prototype declarations for the bots:
void GetMoveBot1(int shots[MAP_SIZE][MAP_SIZE], int *row, int *col);
void GetMoveBot2(int shots[MAP_SIZE][MAP_SIZE], int *row, int *col);
// Gets the input for one move from the human player (an alphabetic row and a numeric column)
// This function converts both inputs to numeric values
void GetMoveHuman(int *row, int *col, int player)
{
char a = ' ';
int b = -1;
printf("Player %d: enter move [row/col]: ", player);
while (!(a >= 'A' && a <= 'Z')) {
scanf("%c", &a);
}
while (!(b >= 0 && b <= 25)) {
scanf("%d", &b);
}
*row = (int)(a - 'A');
*col = b;
}
// Takes two "shots" arrays as input (which are the visible parts of the game shown to players) and formats them into a string for printing
// The player currently to move is highlighted
void GetDisplayMapString(int shots1[MAP_SIZE][MAP_SIZE], int shots2[MAP_SIZE][MAP_SIZE], int player, char *boardString)
{
int i, j;
char numbers[10];
// Intialise board string to be empty:
boardString[0] = '\0';
strcat(boardString, " ");
for (i = 0; i < MAP_SIZE; i++) {
sprintf(numbers, "%d", i%10);
strcat(boardString, numbers);
}
strcat(boardString, "|");
for (i = 0; i < MAP_SIZE; i++) {
sprintf(numbers, "%d", i%10);
strcat(boardString, numbers);
}
strcat(boardString, "\n ");
for (i = 0; i < MAP_SIZE; i++) {
strcat(boardString, "-");
}
strcat(boardString, "|");
for (i = 0; i < MAP_SIZE; i++) {
strcat(boardString, "-");
}
strcat(boardString, "\n");
for (i = 0; i < MAP_SIZE; i++) {
int len = strlen(boardString);
boardString[len] = (char)('A' + i);
boardString[len+1] = '\0';
strcat(boardString, "|");
for (j = 0; j < MAP_SIZE; j++) {
if (shots1[i][j] / HIT > 0) {
if (shots1[i][j] / HIT == 1) {
strcat(boardString, "X");
} else {
sprintf(numbers, "%d", shots1[i][j] / HIT);
strcat(boardString, numbers);
}
} else if (shots1[i][j] > 0) {
strcat(boardString, ".");
} else {
strcat(boardString, " ");
}
}
strcat(boardString, "|");
for (j = 0; j < MAP_SIZE; j++) {
if (shots2[i][j] / HIT > 0) {
if (shots2[i][j] / HIT == 1) {
strcat(boardString, "X");
} else {
sprintf(numbers, "%d", shots2[i][j] / HIT);
strcat(boardString, numbers);
}
} else if (shots2[i][j] > 0) {
strcat(boardString, ".");
} else {
strcat(boardString, " ");
}
}
strcat(boardString, "|");
len = strlen(boardString);
boardString[len] = (char)('A' + i);
boardString[len+1] = '\0';
strcat(boardString, "\n");
}
if (player == 1) {
strcat(boardString, " P1");
for (i = 0; i < MAP_SIZE-2; i++) {
strcat(boardString, "*");
}
} else {
for (i = 0; i < MAP_SIZE; i++) {
strcat(boardString, " ");
}
strcat(boardString, " P2");
for (i = 0; i < MAP_SIZE-2; i++) {
strcat(boardString, "*");
}
}
strcat(boardString, "\n");
}
// Plays one game of Battleships, beginning with the specified starting player
// Game type = 1 (human vs human) or 2 (human vs bot) or 3 (bot vs bot)
int PlayOneGame(int startingPlayer, int gameType)
{
int row, col, player, gameOver;
// String to display the boards
char displayBoardString[(2*MAP_SIZE+5)*(MAP_SIZE+5)];
// The maps containing the locations of the ships
int mapPlayer1[MAP_SIZE][MAP_SIZE] = {0};
int mapPlayer2[MAP_SIZE][MAP_SIZE] = {0};
// The locations of the shots
int shotsPlayer1[MAP_SIZE][MAP_SIZE] = {0};
int shotsPlayer2[MAP_SIZE][MAP_SIZE] = {0};
player = startingPlayer;
gameOver = 0;
// Create random maps for each player
InitialiseRandomMap(mapPlayer1);
InitialiseRandomMap(mapPlayer2);
// Display the board if a human is playing
if (gameType != 3) {
GetDisplayMapString(shotsPlayer1, shotsPlayer2, player, displayBoardString);
printf("%s", displayBoardString);
}
// Process one move for the current player
while (!gameOver) {
if (gameType == 1) {
GetMoveHuman(&row, &col, player);
if (player == 1) {
FireShot(shotsPlayer1, mapPlayer2, row, col);
gameOver = CheckGameOver(shotsPlayer1, mapPlayer2);
} else {
FireShot(shotsPlayer2, mapPlayer1, row, col);
gameOver = CheckGameOver(shotsPlayer2, mapPlayer1);
}
} else if (gameType == 2) {
if (player == 1) {
GetMoveHuman(&row, &col, player);
FireShot(shotsPlayer1, mapPlayer2, row, col);
gameOver = CheckGameOver(shotsPlayer1, mapPlayer2);
} else {
GetMoveBot1(shotsPlayer2, &row, &col);
printf("Player 2 (bot) moves: %c%d\n", (char)(row+'A'), col);
FireShot(shotsPlayer2, mapPlayer1, row, col);
gameOver = CheckGameOver(shotsPlayer2, mapPlayer1);
}
} else {
if (player == 1) {
GetMoveBot1(shotsPlayer1, &row, &col);
FireShot(shotsPlayer1, mapPlayer2, row, col);
gameOver = CheckGameOver(shotsPlayer1, mapPlayer2);
} else {
GetMoveBot2(shotsPlayer2, &row, &col);
FireShot(shotsPlayer2, mapPlayer1, row, col);
gameOver = CheckGameOver(shotsPlayer2, mapPlayer1);
}
}
// Swap players
if (!gameOver) {
player = 3 - player;
}
if (gameType != 3) {
GetDisplayMapString(shotsPlayer1, shotsPlayer2, player, displayBoardString);
printf("%s", displayBoardString);
}
}
return player;
}
// Play a Battleships tournament
// If the tournament is between a human and a bot, only one game is played
// If the tournament is between two bots, the number of games is requested
void PlayBattleships(void)
{
int gameType, numberOfGames, result;
int i, wins1, wins2, player;
// Get play options:
printf("Options:\n");
printf(" [1] = Human vs. Human\n");
printf(" [2] = Human vs. Bot1\n");
printf(" [3] = Bot1 vs. Bot2\n");
printf("Choose game type: ");
scanf("%d", &gameType);
numberOfGames = 1;
result = 0;
// If two bots are playing a tournament, let the user choose how many games
if (gameType == 3) {
printf("Number of games: ");
scanf("%d", &numberOfGames);
}
// Set win counts to zero
wins1 = 0;
wins2 = 0;
// Player 1 will always start the first game
// If a tournament is played (between two bots), the starting player alternates
player = 1;
for (i = 0; i < numberOfGames; i++) {
result = PlayOneGame(player, gameType);
if (result == 1) {
wins1++;
} else {
wins2++;
}
// Switch the starting player for the next game
player = 3 - player;
}
// Show the outcome (of a single game or tournament)
if (numberOfGames == 1) {
printf("\nGame over! Congratulations! Winner is Player %d\n\n", result);
} else {
printf("\nTournament over! Games played = %d\nPlayer 1 wins = %d / Player 2 wins = %d\n\n", numberOfGames, wins1, wins2);
}
}
// The main function for the Battleships program
int main(void)
{
// Initialise the seed for the random number generator
srand((unsigned int)time(NULL));
printf("ENGGEN131 - C Project 2023\n");
printf(" ... presents ...\n");
printf(" ___ __ _____ _____ _ ____ __ _ _ ___ __ \n");
printf("| |_) / /\\ | | | | | | | |_ ( (` | |_| | | | |_) ( (` \n");
printf("|_|_) /_/--\\ |_| |_| |_|__ |_|__ _)_) |_| | |_| |_| _)_) \n");
printf("\n __/___ \n");
printf(" _____/______| \n");
printf(" _______/_____\\_______\\_____ \n");
printf(" \\ < < < | \n");
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("\n");
PlayBattleships();
return 0;
}
/******************************************************************************
*******************************************************************************
*******************************************************************************
// Implementations of the two bots can be provided below
// The existing implementations are naive:
// - Bot 1 simply takes random shots (without checking for repeated shots)
// - Bot 2 also takes random shots (but makes a single test on each turn for a repeated shot)
*******************************************************************************
*******************************************************************************
******************************************************************************/
// Strategy for Bot 1
void GetMoveBot1(int shots[MAP_SIZE][MAP_SIZE], int *row, int *col)
{
int rand_row;
int rand_col;
rand_row = shots[0][0]; // to prevent compiler warning (because otherwise "shots" array is not accessed)
rand_row = rand() % MAP_SIZE;
rand_col = rand() % MAP_SIZE;
*row = rand_row;
*col = rand_col;
}
// Strategy for Bot 2
void GetMoveBot2(int shots[MAP_SIZE][MAP_SIZE], int *row, int *col)
{
int rand_row;
int rand_col;
rand_row = shots[0][0]; // to prevent compiler warning (because otherwise "shots" array is not accessed)
rand_row = rand() % MAP_SIZE;
rand_col = rand() % MAP_SIZE;
// If the shot has been tried before, try one more time
if (shots[rand_row][rand_col] > 0) {
rand_row = rand() % MAP_SIZE;
rand_col = rand() % MAP_SIZE;
}
*row = rand_row;
*col = rand_col;
}