-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbattleshipP3.c
390 lines (328 loc) · 11 KB
/
battleshipP3.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
/* ICSI 333 Programming at the Hardware-Software Interface
* Fall 2019
* Monday 10:25am
* Habib Affinnih
* 001361565
*
* This program models the game Battleship.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#define ROW 10
#define COL 10
#define TOTAL_POSSIBLE_HITS 17
struct node {
char coordinates[3];
char result[20];
struct node *next;
};
void initialize(char ***, char ***);
void place_ship(char ***, char, int);
int position_valid(char **, int, int, int, int);
int input(char *, char *, char **, struct node **);
int promp_input(char *, char *);
void update(char, char, char ***, char **, int *, struct node **, struct node **, struct node **);
void display(char **);
void terminate(char ***, char ***, struct node **);
void insert_node (struct node **, struct node **, struct node **);
/* Initializes the game world.
* char ***world_state: The current world state
* char ***ships: The current ship placement state
*/
void initialize(char ***world_state, char ***ships){
//Allocates memory for the dymanic arrays.
*world_state = (char**)malloc(ROW * sizeof(char*));
*ships = (char**)malloc(ROW * sizeof(char*));
//Fills both arrays with dashes.
for(int i = 0; i < ROW; i++){
(*world_state)[i] = (char*)malloc(COL * sizeof(char));
(*ships)[i] = (char*)malloc(COL * sizeof(char));
for(int j = 0; j < COL; j++){
(*world_state)[i][j] = '-';
(*ships)[i][j] = '-';
}
}
//Declares and initializes the length of the various ships.
const int CARRIER = 5;
const int BATTLESHIP = 4;
const int CRUISER = 3;
const int SUBMARINE = 3;
const int DESTROYER = 2;
place_ship(ships, 'C', CARRIER);
place_ship(ships, 'B', BATTLESHIP);
place_ship(ships, 'R', CRUISER);
place_ship(ships, 'S', SUBMARINE);
place_ship(ships, 'D', DESTROYER);
}
/* Places a ship on the ship board.
* char ***ships: The current ship placement state
* char ship_letter: The letter representing the ship to be placed
* int ship_length: The length of the ship to be placed
*/
void place_ship(char ***ships, char ship_letter, int ship_length){
//Seed the time function.
srand((unsigned) time(NULL));
int startx, starty, orientation;
//Generate starting position variables
do{
startx = rand() % 10;
starty = rand() % 10;
orientation = rand() % 2; //Horizontal = 0, Vertical = 1
}while(position_valid(*ships, startx, starty, orientation, ship_length) != 1);
//Place the ship taking orientation into account.
if(orientation == 0)
for(int i = 0; i < ship_length; i++)
(*ships)[startx + i][starty] = ship_letter;
else
for(int i = 0; i < ship_length; i++)
(*ships)[startx][starty + i] = ship_letter;
}
/* Checks if the provided parameters make a valid location for ship placement.
* char **ships: The current ship placement state
* int x: The horizontal coordinate of the ship to be placed
* int y: The vertical coordinate of the ship to be placed
* int orientation: Integer specifying the orientation of the ship to be placed
* int ship_length: The lenght of the ship to be placed
*
* Returns 1 if the position is valid, and 0 if it is not
*/
int position_valid(char **ships, int x, int y, int orientation, int ship_length){
if(orientation == 0){
if((x + ship_length) > 9)
return 0;
for(int i = 0; i < ship_length; i++)
if((ships[x+i][y]) != '-')
return 0;
return 1;
}
else{
if((y + ship_length) > 9)
return 0;
for(int i = 0; i < ship_length; i++)
if(ships[x][y+i] != '-')
return 0;
return 1;
}
}
/* Gets input from the user.
* char *in_letter: User input letter
* char *in_num: User input number
* char **world_state: The current world state
* struct node **temp: A node to hold the coordinates entered by the user
*
* Returns 0 if the user enters "!" and 1 if they provide valid input
*/
int input(char *in_letter, char *in_num, char **world_state, struct node **temp){
if(promp_input(in_letter, in_num) == 0)
return 0;
int x = toascii(*in_letter) - 65;
int y = (*in_num) - '0';
while(world_state[x][y] != '-'){
printf("\nYou have already entered this postion! Try again!\n");
if(promp_input(in_letter, in_num) == 0)
return 0;
x = toascii(*in_letter) - 65;
y = (*in_num) - '0';
}
//Allocate memory for the node
if (((*temp) = (struct node *)malloc(sizeof(struct node))) == NULL) {
printf("Node allocation failed. \n");
exit(1); /* Stop program */
}
//Concatenate the coordinates
char temp_str[3] = {*in_letter, *in_num};
strcpy((*temp)->coordinates, temp_str);
(*temp)->next = NULL;
return 1;
}
/* Prompts the user for input and validates said input.
* char *in_letter: User input letter
* char *in_num: User input number
*
* Returns 0 if the user enters "Z0" and 1 if they provide valid input
*/
int promp_input(char *in_letter, char *in_num){
int invalid = 1;
do{
printf("Enter a letter A-J and number 0-9 ex. B4 - enter Z0 to end\n");
char temp[20];
fgets(temp, 20, stdin);
if(strlen(temp) != 3){
printf("INVALID INPUT\n");
continue;
}
*in_letter = temp[0];
*in_num = temp[1];
*in_letter = toupper(*in_letter);
if((*in_letter) == 'Z' && (*in_num) == '0'){
return 0;
}
if ((*in_letter) < 65 || (*in_letter) > 74)
printf("Invalid Letter!\n");
else if ((*in_num) < '0' || (*in_num) > '9')
printf("Invalid Number!\n");
else
invalid = 0;
}while(invalid);
return 1;
}
/* Updates the world_state based on the input letter and number the user has entered.
* char in_letter: User letter input
* char in_num: User number input
* char ***world_state: current world_state
* char **ships: The current ship placement state
* int *spots_hit: Integer tracking the number of spots the user has hit
* struct node **h: The head of the linked list
* struct node **t: The tail of the linked list
* struct node **temp: The current node
*/
void update(char in_letter, char in_num, char ***world_state, char **ships, int *spots_hit, struct node **h, struct node **t, struct node **temp){
int x = toascii(in_letter) - 65;
int y = in_num - '0';
switch (ships[x][y])
{
case 'C':
printf("\nYou hit the carrier!");
(*world_state)[x][y] = 'H';
(*spots_hit)++;
strcpy((*temp)->result, "Hit - Carrier");
break;
case 'B':
printf("\nYou hit the battleship!");
(*world_state)[x][y] = 'H';
(*spots_hit)++;
strcpy((*temp)->result, "Hit - Battleship");
break;
case 'R':
printf("\nYou hit the cruiser!");
(*world_state)[x][y] = 'H';
(*spots_hit)++;
strcpy((*temp)->result, "Hit - Cruiser");
break;
case 'S':
printf("\nYou hit the submarine!");
(*world_state)[x][y] = 'H';
(*spots_hit)++;
strcpy((*temp)->result, "Hit - Submarine");
break;
case 'D':
printf("\nYou hit the destroyer!");
(*world_state)[x][y] = 'H';
(*spots_hit)++;
strcpy((*temp)->result, "Hit - Destroyer");
break;
default:
printf("\nYou missed!");
(*world_state)[x][y] = 'M';
strcpy((*temp)->result, "Miss");
break;
}
insert_node(h, t, temp);
}
/* Displays the current state of the world.
* char **world_state: The current world state.
*/
void display(char **world_state){
char c = 'A';
//Prints the number row above the game board
printf("\n");
for(int i = -1; i < COL; i++){
if(i >= 0)
printf("%d ", i);
else
printf(" ");
}
printf("\n");
//Prints the game board with the corresponding letters before each row
for(int i = 0; i < ROW; i++){
printf("%c ", c + (i));
for(int j = 0; j < COL; j++)
printf("%c ", world_state[i][j]);
printf("\n");
}
}
/* Terminates the game world.
* char ***world_state: The current world state
* char ***ships: The current ship placement state
* char **head: The head of the linked list
*/
void terminate(char ***world_state, char ***ships, struct node **head){
for(int i = 0; i < ROW; i++){
free((*world_state)[i]);
free((*ships)[i]);
}
free(*world_state);
free(*ships);
FILE *fp = fopen("move_log.txt", "w");
if ((fp = fopen("move_log.txt", "w")) == NULL){
/* File open failed. */
printf("Can’t open in.dat.\n"); exit(1);
}
while(*head != NULL){
fprintf(fp, "Fired at %s. %s. \n", (*head)->coordinates, (*head)->result);
struct node *temp = *head;
*head = (*head)->next;
free(temp);
}
if (fclose(fp) == EOF) { /* Error in closing output file */
printf("Error in closing log file.\n");
}
}
/* Inserts the provided node into the end of the linked list.
* struct node **h: The head of the linked list
* struct node **t: The tail of the linked list
* struct node **temp: The node to be inserted
*/
void insert_node (struct node **h, struct node **t, struct node **temp) {
if (*h == NULL) {
/* List is currently empty. */
*h = *t = *temp;
}
else { /* The list is not empty. Use *t to add the node */
/* at the end. */
(*t)->next = *temp; *t = (*t)->next;
}
}
//Loops through the game's main structure.
int main(){
char **world_state; //Dynamic array modeling the state of the world.
char **ships; //Dynamic array modeling the placement of ships on the board.
char input_letter = 'A'; //Variable to hold the user's letter input.
char input_number = '0'; //Variable to hold the user's number input.
int spots_hit = 0; //Variable to keep track of how many spots the player has hit.
int moves = 0; //Variable to track the number of moves the player has made.
struct node *head, *tail, *temp; //Nodes for linked list
head = tail = NULL;
//Initializes the world_state and ship placement.
initialize(&world_state, &ships);
//Prints the location of the ships
printf("\nThis is the placement of ships for this game:\n");
display(ships);
printf("\nSink all the ships to win! Enter \"!\" at anytime to quit the game.\n");
display(world_state);
//Main game loop. It runs until the user stops it by entering "!".
while((spots_hit < TOTAL_POSSIBLE_HITS) && (input(&input_letter, &input_number, world_state, &temp) == 1)){
update(input_letter, input_number, &world_state, ships, &spots_hit, &head, &tail, &temp); //Updates the world_state
moves++;
if(spots_hit != 16)
printf("\nYou have %d more spots to hit!\n", TOTAL_POSSIBLE_HITS - spots_hit);
else
printf("\nYou have %d more spot to hit!\n", TOTAL_POSSIBLE_HITS - spots_hit);
display(world_state); //Displays the world_state
}
//Checks if the player sunk all the ships.
if(spots_hit == 17)
printf("\nCongratulations! You sunk all the ships in %d moves!\nHere's a cookie\n", moves);
else{
printf("You quit after %d moves.\nThis is where the ships were:\n", moves);
display(ships);
}
//Terminates the game
terminate(&world_state, &ships, &head);
printf("Press any key to exit.");
getchar();
return 0;
}