-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame.c
More file actions
278 lines (250 loc) · 9.74 KB
/
game.c
File metadata and controls
278 lines (250 loc) · 9.74 KB
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
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define MAX_USERNAME_LENGTH 128 /* Maksymalna dlugosc nazwy uzytkownika */
/* Struktura reprezentujaca wiadomosc w grze */
struct message {
char username[MAX_USERNAME_LENGTH]; /* Nazwa uzytkownika */
int value; /* Podstawowa wartosc komunikacyjna */
};
int sockfd; /* Deskryptor gniazda */
char ip[INET_ADDRSTRLEN]; /* Adres IP drugiego gracza */
char my_username[MAX_USERNAME_LENGTH]; /* Nazwa tego gracza */
char other_username[MAX_USERNAME_LENGTH]; /* Nazwa drugiego gracza */
struct message msg; /* Wiadomosc */
struct sockaddr_in other_addr; /* Struktura adresu drugiego gracza */
socklen_t other_addr_len = sizeof(other_addr); /* Dlugosc struktury adresu */
int score[2] = {0}; /* Wynik gry */
int my_turn = 0; /* Zmienna informujaca o kolejnosci ruchu */
int started = 0; /* Flaga informujaca kto zaczal */
int no_game = 1; /* Flaga informujaca o braku aktywnej gry */
pid_t pid = -1; /* Identyfikator procesu potomnego */
pid_t ppid = 0; /* Identyfikator procesu rodzica */
void sighandler(int signal); /* Obsluga sygnalow */
void process_input(); /* Przetwarzanie wejscia od uzytkownika */
void process_message(); /* Przetwarzanie otrzymanej wiadomosci */
void setup_network(char *arg1, char *arg2); /* Konfiguracja sieciowa */
void start_game(); /* Rozpoczecie gry */
/* Funkcja glowna */
int main(int argc, char *argv[]) {
ssize_t bytes_read = 0;
ppid = getpid();
srand(time(NULL));
/* Ustawienie obslugi sygnalow */
if (signal(SIGUSR1, sighandler) == SIG_ERR)
perror("signal");
if (signal(SIGUSR2, sighandler) == SIG_ERR)
perror("signal");
/* Sprawdzenie poprawnosci argumentow wywolania programu */
if (argc == 3) {
memset(my_username, '\0', MAX_USERNAME_LENGTH);
} else if (argc == 4) {
strncpy(my_username, argv[3], MAX_USERNAME_LENGTH);
} else {
printf("Bledna liczba argumentow!\n");
exit(EXIT_FAILURE);
}
if ((atoi(argv[2])) <= 0) {
printf("Bledny numer portu!\n");
}
/* Konfiguracja polaczenia sieciowego */
setup_network(argv[1], argv[2]);
printf("Gra w 50, wersja A.\n");
printf("Rozpoczynam gre z %s. Napisz \"koniec\" aby zakonczyc lub \"wynik\" by wyswietlic aktualny wynik.\n", ip);
/* Wyslanie propozycji gry */
msg.value = -1;
strncpy(msg.username, my_username, MAX_USERNAME_LENGTH);
if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&other_addr, sizeof(other_addr)) == -1)
perror("sendto");
printf("Propozycja gry wyslana.\n");
/* Glowna petla programu */
for (;;) {
/* Obsluga wiadomosci jesli jakas zostala odebrana */
if (bytes_read > 0) {
process_message();
}
/* Utworzenie procesu potomnego do asynchronicznej obslugi wejscia */
if (pid == -1) {
pid = fork();
if (pid == -1)
perror("fork");
if (pid == 0)
process_input();
}
memset(&bytes_read, 0, sizeof(bytes_read));
memset(&msg, 0, sizeof(msg));
bytes_read = recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&other_addr, &other_addr_len);
if (bytes_read == -1)
perror("recvfrom");
}
}
/* Konfiguracja polaczenia sieciowego */
void setup_network(char *arg1, char *arg2) {
struct addrinfo *result, hints;
int s;
struct sockaddr_in my_addr;
/* Utworzenie gniazda */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
perror("socket");
/* Inicjalizacja struktury adresu dla gniazda lokalnego */
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_port = htons(atoi(arg2));
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1)
perror("bind");
/* Konfiguracja struktury hints */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
/* Pobranie informacji o adresie drugiego gracza */
if ((s = getaddrinfo(arg1, arg2, &hints, &result)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* Skopiowanie informacji o adresie drugiego gracza */
other_addr = *(struct sockaddr_in *)result->ai_addr;
freeaddrinfo(result);
/* Konwersja adresu IP na tekstowa reprezentacje */
inet_ntop(other_addr.sin_family, &other_addr.sin_addr, ip, sizeof(ip));
}
/* Przetwarzanie otrzymanej wiadomosci */
void process_message() {
my_turn = 1;
if (pid > 0) {
if (kill(pid, SIGTERM) == -1) /* Proces potomny jest zabijany przy kazdej otrzymanej wiadomosci */
perror("kill"); /* nastepnie jest tworzony ponownie, pozwala to na utrzymanie spojnosci danych */
if (wait(NULL) == -1) /* miedzy potomkiem i rodzicem bez potrzeby komunikacji miedzyprocesowej */
perror("wait");
printf("\n");
pid = -1;
}
if (msg.username[0] == '\0')
strncpy(msg.username, ip, MAX_USERNAME_LENGTH);
strncpy(other_username, msg.username, MAX_USERNAME_LENGTH);
/* Obsluga otrzymanych wiadomosci */
/* Komunikacja odbywa sie za pomoca zmiennej value w strukturze message. */
/* wartosci dodatnie sluza do gry, wartosci ujemne oznaczaja specjalna akcje */
/* -1 wiadomosc poczatkowa (inny gracz dolaczyl) */
/* -2 zakonczenie gry przez drugiego gracza */
/* -3 ktorys z graczy wygral, rozpoczecie nastepnej rundy */
if (msg.value == -1) {
printf("%s dolaczyl do gry.\n", other_username);
memset(score, 0, sizeof(score));
start_game();
} else if (msg.value == -2) {
printf("%s zakonczyl gre, mozesz poczekac na kolejnego gracza.\n", other_username);
my_turn = 0;
msg.value = 0;
no_game = 1;
} else if (msg.value == 50) {
printf("%s podal wartosc 50.\nPrzegrana!\n", other_username);
score[1]++;
msg.value = -3;
if (started == 1) {
started = 0;
printf("Zaczynamy kolejna rozgrywke. Poczekaj na swoja kolej.\n");
my_turn = 0;
}
} else if (msg.value == -3) {
if (started == 0) {
printf("Zaczynamy kolejna rozgrywke.\n");
start_game();
} else {
started = 0;
printf("Zaczynamy kolejna rozgrywke. Poczekaj na swoja kolej.\n");
my_turn = 0;
}
} else {
printf("%s wybral wartosc %d, podaj kolejna wartosc.\n", other_username, msg.value);
no_game = 0;
}
}
/* Obsluga sygnalow */
void sighandler(int signal) {
if (signal == SIGUSR1) { /* gracz wpisal komende koniec */
if (wait(NULL) == -1)
perror("wait");
if (close(sockfd) == -1)
perror("close");
exit(EXIT_SUCCESS);
}
if (signal == SIGUSR2) /* gracz wygral */
score[0]++;
}
/* Przetwarzanie wejscia od uzytkownika */
void process_input() {
for (;;) {
for (;;) {
if (msg.value == -3 || msg.value == -2)
break;
int value;
char input[16];
printf("> ");
scanf("%s", input);
if (strcmp(input, "koniec") == 0) {
msg.value = -2;
break;
} else if (strcmp(input, "wynik") == 0) {
if (no_game == 0)
printf("Ty %d : %d %s\n", score[0], score[1], strlen(other_username) > 0 ? other_username : "Gracz2");
else
printf("Poczekaj na dolaczenie innego gracza\n");
} else {
value = atoi(input);
if (my_turn == 1 && no_game == 0) {
if (value <= msg.value || value > msg.value + 10 || value > 50)
printf("Takiej wartosci nie mozesz wybrac!\n");
else {
msg.value = value;
my_turn = 0;
break;
}
} else {
if (no_game == 1)
printf("Poczekaj na dolaczenie innego gracza\n");
else
printf("Teraz tura gracza %s, poczekaj na swoja kolej\n", other_username);
}
}
}
strncpy(msg.username, my_username, MAX_USERNAME_LENGTH);
if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&other_addr, other_addr_len) == -1)
perror("sendto");
/* Komunikacja z rodzicem odbywa sie poprzez sygnaly */
if (msg.value == 50) {
printf("Wygrana!\n");
msg.value = 0;
kill(ppid, SIGUSR2);
}
if (msg.value == -2) {
kill(ppid, SIGUSR1);
exit(EXIT_SUCCESS);
}
if (msg.value == -3) {
msg.value = 0;
}
}
}
/* Rozpoczecie gry */
void start_game() {
started = 1;
no_game = 0;
msg.value = rand() % 10 + 1;
printf("Losowa wartosc poczatkowa: %d, podaj kolejna wartosc.\n", msg.value);
}