-
Notifications
You must be signed in to change notification settings - Fork 0
/
battleShip.c
438 lines (400 loc) · 14.1 KB
/
battleShip.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
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/*
Project Group 2
UTKU AKKUŞOĞLU
MEHMET GÖKGÜL
EFE BEKİR ALTOP
ALİ BATUHAN ZEYTÜN
BATUHAN TUNÇER
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <ncurses.h>
#define GRID_SIZE 8
typedef struct { // shared memory items
char grid1[GRID_SIZE][GRID_SIZE];
char grid2[GRID_SIZE][GRID_SIZE];
int coordinatesHitBy1;
int coordinatesHitBy2;
int isOver;
int currentPlayer;
int isFirstStart;
int player1Attacks[GRID_SIZE][GRID_SIZE];
int player2Attacks[GRID_SIZE][GRID_SIZE];
} GameState;
typedef struct {
int size;
char symbol;
} Ship;
void createInitialGrid(char grid[GRID_SIZE][GRID_SIZE]);
void displayGrid(char grid[GRID_SIZE][GRID_SIZE]);
int canPlaceShip(char grid[GRID_SIZE][GRID_SIZE], int x, int y, int size, int isHorizontal);
void placeShip(char grid[GRID_SIZE][GRID_SIZE], Ship ship);
void saveGameState(GameState *game_state);
void loadGameState(GameState *game_state);
void displaySavedGameState();
void showMenu();
void startGame(GameState* game_state);
void showGrids(GameState* game_state);
void relocateShips(GameState* game_state);
void exitProgram(int shm_fd, const char* name);
int* ai(char last_successful_hit[2], int playerAttacks[GRID_SIZE][GRID_SIZE]);
GameState *game_state;
const char *filename = "game_bs.dat";
int main() {
const int SIZE = sizeof(GameState);
const char* name = "BattleShip";
int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SIZE);
game_state = mmap(0, SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, shm_fd, 0);
game_state->isFirstStart = 1;
srand(time(0));
initscr();
start_color();
init_pair(1, COLOR_BLUE, COLOR_BLACK); // for Battlehip(B)
init_pair(2, COLOR_GREEN, COLOR_BLACK); // for Cruisers(C)
init_pair(3, COLOR_YELLOW, COLOR_BLACK); // for Destroyers(D)
init_pair(4, COLOR_RED, COLOR_BLACK); // for hit mark(X)
cbreak();
keypad(stdscr, TRUE);
scrollok(stdscr, TRUE);
mousemask(0, NULL);
int choice;
while (1) {
showMenu();
printw("Enter choice: ");
refresh();
choice = getch() - '0';
printw("\n");
refresh();
switch (choice) {
case 1:
startGame(game_state);
break;
case 2:
showGrids(game_state);
break;
case 3:
relocateShips(game_state);
break;
case 4:
saveGameState(game_state);
printw("Saving game and exiting...");
refresh();
exitProgram(shm_fd, name);
refresh();
return 0;
case 5:
loadGameState(game_state);
break;
case 6:
displaySavedGameState();
break;
default:
printw("Invalid choice. Please select again.");
refresh();
break;
}
}
refresh();
}
void showMenu() {
printw("\n--- Game Menu ---\n");
printw("1. Start New Game\n");
printw("2. Show Grids\n");
printw("3. Relocate Ships\n");
printw("4. Save Game and Exit\n");
printw("5. Load Saved Game\n");
printw("6. Display Saved Game State\n\n");
refresh();
}
void createInitialGrid(char grid[GRID_SIZE][GRID_SIZE]) {
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
grid[i][j] = '#';
}
}
Ship ships[] = { {4, 'B'}, {3, 'C'}, {3, 'C'}, {2, 'D'}, {2, 'D'} };
int num_ships = sizeof(ships) / sizeof(ships[0]);
for (int i = 0; i < num_ships; i++) {
placeShip(grid, ships[i]);
}
}
int canPlaceShip(char grid[GRID_SIZE][GRID_SIZE], int x, int y, int size, int isHorizontal) {
for (int i = 0; i < size; i++) {
int nx = x + (isHorizontal ? 0 : i);
int ny = y + (isHorizontal ? i : 0);
if (nx >= GRID_SIZE || ny >= GRID_SIZE || grid[nx][ny] != '#') {
return 0;
}
if ((nx > 0 && grid[nx - 1][ny] != '#') || // control of upper
(nx < GRID_SIZE - 1 && grid[nx + 1][ny] != '#') || // control of down
(ny > 0 && grid[nx][ny - 1] != '#') || // control of left
(ny < GRID_SIZE - 1 && grid[nx][ny + 1] != '#') || // control of right
(nx > 0 && ny > 0 && grid[nx - 1][ny - 1] != '#') || // control of upper left
(nx > 0 && ny < GRID_SIZE - 1 && grid[nx - 1][ny + 1] != '#') || // control of upper right
(nx < GRID_SIZE - 1 && ny > 0 && grid[nx + 1][ny - 1] != '#') || // control of down left
(nx < GRID_SIZE - 1 && ny < GRID_SIZE - 1 && grid[nx + 1][ny + 1] != '#')) { // control of down right
return 0;
}
}
return 1;
}
void placeShip(char grid[GRID_SIZE][GRID_SIZE], Ship ship) {
int x, y, isHorizontal;
do {
x = rand() % GRID_SIZE;
y = rand() % GRID_SIZE;
isHorizontal = rand() % 2;
} while (!canPlaceShip(grid, x, y, ship.size, isHorizontal));
for (int i = 0; i < ship.size; i++) {
int nx = x + (isHorizontal ? 0 : i);
int ny = y + (isHorizontal ? i : 0);
grid[nx][ny] = ship.symbol;
}
}
void displayGrid(char grid[GRID_SIZE][GRID_SIZE]) {
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (grid[i][j] == 'B') {
attron(COLOR_PAIR(1));
printw("%c ", grid[i][j]);
attroff(COLOR_PAIR(1));
} else if (grid[i][j] == 'C') {
attron(COLOR_PAIR(2));
printw("%c ", grid[i][j]);
attroff(COLOR_PAIR(2));
} else if (grid[i][j] == 'D') {
attron(COLOR_PAIR(3));
printw("%c ", grid[i][j]);
attroff(COLOR_PAIR(3));
} else if (grid[i][j] == 'X') {
attron(COLOR_PAIR(4));
printw("%c ", grid[i][j]);
attroff(COLOR_PAIR(4));
} else {
printw("%c ", grid[i][j]);
}
}
printw("\n");
}
refresh();
}
void saveGameState(GameState *game_state) {
FILE *file = fopen(filename, "wb");
fwrite(game_state, sizeof(GameState), 1, file);
fclose(file);
}
void loadGameState(GameState *game_state) {
if (access(filename, F_OK) == -1) {
printw("No saved game found. Starting a new game.\n\n");
refresh();
return;
}
FILE *file = fopen(filename, "rb");
if (file) {
if (fread(game_state, sizeof(GameState), 1, file) != 1) {
printw("Error loading game state. The file may be corrupted.\n\n");
refresh();
} else {
printw("Game state loaded.\n\n");
refresh();
}
fclose(file);
} else {
printw("Error opening file.\n\n");
refresh();
}
}
void displaySavedGameState() {
FILE *file = fopen(filename, "rb");
if (file) {
fread(game_state, sizeof(GameState), 1, file);
printw("\nSaved Player1's grid:\n");
displayGrid(game_state->grid1);
printw("Saved Player2's grid:\n");
displayGrid(game_state->grid2);
printw("Coordinates hit by Player1: %d\n", game_state->coordinatesHitBy1);
printw("Coordinates hit by Player2: %d\n\n", game_state->coordinatesHitBy2);
fclose(file);
refresh();
} else {
printw("No saved game found.\n\n");
refresh();
}
}
void startGame(GameState* game_state) {
if (game_state->isFirstStart == 1 || game_state->isOver == 1) {
relocateShips(game_state);
game_state->isOver = 0;
}
printw("\nPlayer1's initial grid:\n");
displayGrid(game_state->grid1);
printw("\nPlayer2's initial grid:\n");
displayGrid(game_state->grid2);
printw("-------------------------------------------------\n");
refresh();
pid_t pid = fork();
srand(getpid());
int last_shot_player1 = 0; // Was player1's last hit successful?
int last_shot_player2 = 0; // Was player2's last hit successful?
char last_successful_hit1[2]; // Coordinate of player1's last successful hit
char last_successful_hit2[2]; // Coordinate of player2's last successful hit
char last_hit_ship_by_player1; // type of last hit ship(B, C, D) by player1
char last_hit_ship_by_player2; // type of last hit ship(B, C, D) by player2
if (pid < 0) {
fprintf(stderr, "Fork failed!\n");
exit(1);
} else if (pid == 0) {
while (game_state->isOver != 1) {
if (game_state->currentPlayer == 2) {
int x, y;
if(last_shot_player2 == 1){
int *choice = ai(last_successful_hit2, game_state->player2Attacks);
x = choice[0];
y = choice[1];
}
else{
do {
x = rand() % GRID_SIZE;
y = rand() % GRID_SIZE;
}while (game_state->player2Attacks[x][y]);
}
printw("Player2's choice is (%d,%d) -> ", x, y);
refresh();
int hit = (game_state->grid1[x][y] != '#');
game_state->player2Attacks[x][y] = 1;
if (hit) {
last_shot_player2 = 1;
last_hit_ship_by_player2 = game_state->grid1[x][y];
game_state->grid1[x][y] = 'X';
last_successful_hit2[0] = x;
last_successful_hit2[1] = y;
game_state->coordinatesHitBy2++;
saveGameState(game_state);
printw("Player2 hit a ship part and game saved\n");
refresh();
displayGrid(game_state->grid1);
} else {
printw("Player2 missed\n");
refresh();
last_shot_player2 = 0;
}
if (game_state->coordinatesHitBy2 == 14) {
game_state->isOver = 1;
printw("Player2 won!\n");
}
game_state->currentPlayer = 1;
}
sleep(1);
refresh();
}
exit(0);
} else {
while (game_state->isOver != 1) {
if (game_state->currentPlayer == 1) {
int x, y;
if(last_shot_player1 == 1){
int *choice = ai(last_successful_hit1, game_state->player1Attacks);
x = choice[0];
y = choice[1];
}
else{
do {
x = rand() % GRID_SIZE;
y = rand() % GRID_SIZE;
} while (game_state->player1Attacks[x][y]);
}
printw("Player1's choice is (%d,%d) -> ", x, y);
refresh();
int hit = (game_state->grid2[x][y] != '#');
game_state->player1Attacks[x][y] = 1;
if (hit) {
last_shot_player1 = 1;
last_hit_ship_by_player1 = game_state->grid2[x][y];
game_state->grid2[x][y] = 'X';
last_successful_hit1[0] = x;
last_successful_hit1[1] = y;
game_state->coordinatesHitBy1++;
saveGameState(game_state);
printw("Player1 hit a ship part and game saved\n");
refresh();
displayGrid(game_state->grid2);
} else {
printw("Player1 missed\n");
refresh();
last_shot_player1 = 0;
}
if (game_state->coordinatesHitBy1 == 14) {
game_state->isOver = 1;
printw("Player1 won!\n");
}
game_state->currentPlayer = 2;
}
sleep(1);
refresh();
}
wait(NULL);
}
}
void showGrids(GameState* game_state) {
printw("\nPlayer1's grid:\n");
displayGrid(game_state->grid1);
printw("\nPlayer2's grid:\n");
displayGrid(game_state->grid2);
printw("-------------------------------------------------\n\n");
refresh();
}
void relocateShips(GameState* game_state) {
createInitialGrid(game_state->grid1);
createInitialGrid(game_state->grid2);
game_state->coordinatesHitBy1 = 0;
game_state->coordinatesHitBy2 = 0;
game_state->isOver = 0;
game_state->currentPlayer = 1;
game_state->isFirstStart = 0;
memset(game_state->player1Attacks, 0, sizeof(game_state->player1Attacks));
memset(game_state->player2Attacks, 0, sizeof(game_state->player2Attacks));
printw("Ships located!\n\n");
refresh();
}
int* ai(char last_successful_hit[2], int playerAttacks[GRID_SIZE][GRID_SIZE]){
int x = last_successful_hit[0];
int y = last_successful_hit[1];
int* choice = malloc(2 * sizeof(int));
if(x + 1 < GRID_SIZE && playerAttacks[x + 1][y] != 1){
x++;
}
else if(x - 1 >= 0 && playerAttacks[x - 1][y] != 1){
x--;
}
else if(y + 1 < GRID_SIZE && playerAttacks[x][y + 1] != 1){
y++;
}
else if(y - 1 >= 0 && playerAttacks[x][y - 1] != 1){
y--;
}
else{
do {
x = rand() % GRID_SIZE;
y = rand() % GRID_SIZE;
} while (playerAttacks[x][y]);
}
choice[0] = x;
choice[1] = y;
return choice;
}
void exitProgram(int shm_fd, const char* name) {
endwin();
printw("Exiting...\n");
refresh();
close(shm_fd);
shm_unlink(name);
exit(0);
}