-
Notifications
You must be signed in to change notification settings - Fork 0
/
GameOfLife_curiosity.c
564 lines (490 loc) · 28.1 KB
/
GameOfLife_curiosity.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
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "mpi.h"
#define ALIVE 'a'
#define DEAD 'd'
#define ALIVE_EMOJI "🦠"
#define DEAD_EMOJI "⬛"
#define SOSTITUISCI_CON_DEAD_EMOJI "💀"
/* DESCRIZIONE CODICE
? compili codice: mpicc GameOfLife_curiosity.c -o curiosity
! esempio di esecuzione: mpirun --allow-run-as-root -np 2 curiosity 1 10
! mpirun --allow-run-as-root -np 2 curiosity {choice} {GENERAZIONI}
*/
//Stampa matrice
void print_array_int(int arr[], int dim) {
for (int i=0; i<dim; i++)
printf("%d ", arr[i]);
printf("\n");
}
void print_array_float(float arr[], int dim) {
for (int i=0; i<dim; i++)
printf("%.1f ", arr[i]);
printf("\n");
}
void print_array_char(char arr[], int dim) {
for (int i=0; i<dim; i++)
printf("%c ", arr[i]);
printf("\n");
}
void printMatrixEmoji(char *matrix, int ROW_SIZE, int COL_SIZE) {
char c;
for (int i = 0; i < ROW_SIZE; i++) {
printf("[");
for (int j = 0; j < COL_SIZE; j++) {
c = matrix[j + (i * COL_SIZE)];
if (j==COL_SIZE-1) { //Non mi trovo vicino al bordo e quindi NON aggiungo uno spazio a destra
if (c == ALIVE) {
printf("%s", ALIVE_EMOJI);
}
else {
printf("%s", DEAD_EMOJI);
}
}
else {//Mi trovo vicino al bordo e quindi AGGIUNGO uno spazio a destra
if (c == ALIVE) {
printf("%s ", ALIVE_EMOJI);
}
else {
printf("%s ", DEAD_EMOJI);
}
}
}
printf("]\n");
}
}
void printMatrix(char *matrix, int ROW_SIZE, int COL_SIZE) {
char c;
for (int i = 0; i < ROW_SIZE; i++) {
printf("[");
for (int j = 0; j < COL_SIZE; j++) {
c = matrix[j + (i * COL_SIZE)];
if (j==COL_SIZE-1) {
printf("%c", c);
}
else {
printf("%c ", c);
}
}
printf("]\n");
}
}
//Distribuisce in maniera equa (se possibile) le righe di una matrice ai diversi processori
void initDisplacementPerProcess(int send_counts[], int displacements[], int rowPerProcess[], int nprocs, int resto, int divisione, int COL_SIZE) {
for (int i = 0; i < nprocs; i++) {
rowPerProcess[i] = (i < resto) ? divisione + 1 : divisione; //calcolo il numero di righe per processo, se riesce equamente altrimenti una riga in più ai processi con rank<resto
send_counts[i] = (rowPerProcess[i]) * COL_SIZE; //calcolo il numero di elementi per ogni processo in base al numero di righe
displacements[i] = i == 0 ? 0 : displacements[i - 1] + send_counts[i - 1]; //calcolo il displacements tra gli elementi dei processi
}
}
//Funzioni di Inizializzazione matrice
void generateMatrix(char *matrix, int ROW_SIZE, int COL_SIZE) {
int k=0;
for (int i = 0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++, k++) {
if (rand() % 2 == 0) {
matrix[j + (i * COL_SIZE)] = DEAD;
} else
matrix[j + (i * COL_SIZE)] = ALIVE;
}
}
}
void generateStaticMatrix(char *matrix, int ROW_SIZE, int COL_SIZE, int choice) {
if (choice==1) {
// ROW_SIZE: 20, COL_SIZE: 38
char static_matrix[] = {
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*1 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0', /*2 riga*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1','0','1','0','0','0','0','0','0','0','0','0','0','0','0', /*3 riga*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','1','1','0','0','0','0','0','0','1','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*4 riga*/
'0','0','0','0','0','0','0','0','0','0','0','0','1','0','0','0','1','0','0','0','0','1','1','0','0','0','0','0','0','0','0','0','0','0','0','1','1','0', /*5 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','1','0','0','0','0','0','1','0','0','0','1','1','0','0','0','0','0','0','0','0','0','0','0','0','1','1','0', /*6 RIGA*/
'0','1','1','0','0','0','0','0','0','0','0','1','0','0','0','1','0','1','1','0','0','0','0','1','0','1','0','0','0','0','0','0','0','0','0','0','0','0', /*7 RIGA*/
'0','1','1','0','0','0','0','0','0','0','0','1','0','0','0','0','0','1','0','0','0','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0', /*8 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','1','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*9 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','1','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*10 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*11 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*12 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*13 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*14 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*15 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*16 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*17 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*18 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*19 FUORI CAMPO*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' /*20 FUORI CAMPO*/
};
//printf("Length: %d\n", sizeof(static_matrix)/sizeof(static_matrix[0]));
int k=0;
for (int i = 0, x=0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++, k++, x++) {
if (static_matrix[x] == '0') {
matrix[j + (i * COL_SIZE)] = DEAD;
} else
matrix[j + (i * COL_SIZE)] = ALIVE;
}
}
}
else if (choice == 2) {
//ROW_SIZE: 19, COL_SIZE: 21
char static_matrix2[] = {
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*1 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*2 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*3 RIGA*/
'0','0','0','0','0','0','1','1','1','0','0','0','1','1','1','0','0','0','0','0','0', /*4 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*5 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*6 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*7 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*8 RIGA*/
'0','0','0','0','0','0','1','1','1','0','0','0','1','1','1','0','0','0','0','0','0', /*9 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*10 RIGA*/
'0','0','0','0','0','0','1','1','1','0','0','0','1','1','1','0','0','0','0','0','0', /*11 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*12 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*13 RIGA*/
'0','0','0','0','1','0','0','0','0','1','0','1','0','0','0','0','1','0','0','0','0', /*14 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*15 RIGA*/
'0','0','0','0','0','0','1','1','1','0','0','0','1','1','1','0','0','0','0','0','0', /*16 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*17 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', /*18 RIGA*/
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' /*19 RIGA*/
};
//printf("Length: %d\n", sizeof(static_matrix2)/sizeof(static_matrix2[0]));
int k=0;
for (int i = 0, x=0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++, k++, x++) {
if (static_matrix2[x] == '0') {
matrix[j + (i * COL_SIZE)] = DEAD;
} else
matrix[j + (i * COL_SIZE)] = ALIVE;
}
}
}
}
//Funzione che permette di ricostruire la sottomatrice del processo una volta ricevute le due righe
//dai processi adiacenti (bottomRow e topRow)
void rebuildMatrix(char *matrixrec, int rows, char bottomRow[], char topRow[], char *rebuildedMatrix, int COL_SIZE) {
int step = 0;
for (int i = 0; i < 1; i++) { //Inserimento della prima riga
for (int j = step, z = 0; j < step + COL_SIZE; j++, z++) {
rebuildedMatrix[j] = bottomRow[z];
}
step = step + COL_SIZE;
}
int step1 = 0;
for (int i = 0; i < rows; i++) { //Inserimento della matrice in mezzo
for (int j = step1, z = step; j < step1 + COL_SIZE && z < step + COL_SIZE; j++, z++) {
rebuildedMatrix[z] = matrixrec[j];
}
step = step + COL_SIZE;
step1 = step1 + COL_SIZE;
}
for (int i = rows + 1; i < rows + 2; i++) { //Inserimento dell'ultima riga
for (int j = step, z = 0; j < step + COL_SIZE; j++, z++) {
rebuildedMatrix[j] = topRow[z];
}
}
}
void rebuildMatrix2(char *matrixrec, int edge_or_center, int rows, char bottomRow[], char topRow[], char *rebuildedMatrix, int COL_SIZE) {
if (edge_or_center == 0) { //Inserimento righe estreme
int step = 0;
for (int i = 0; i < 1; i++) { //Inserimento prima riga
for (int j = step, z = 0; j < step + COL_SIZE; j++, z++) {
rebuildedMatrix[j] = bottomRow[z];
}
step = step + COL_SIZE;
}
step = COL_SIZE + (rows * COL_SIZE);
for (int i = rows + 1; i < rows + 2; i++) { //Inserimento ultima riga
for (int j = step, z = 0; j < step + COL_SIZE; j++, z++) {
rebuildedMatrix[j] = topRow[z];
}
}
}
else if (edge_or_center == 1) { //Inserimento matrice centrale
int step = COL_SIZE;
int step1 = 0;
for (int i = 0; i < rows; i++) {
for (int j = step1, z = step; j < step1 + COL_SIZE && z < step + COL_SIZE; j++, z++) {
rebuildedMatrix[z] = matrixrec[j];
}
step = step + COL_SIZE;
step1 = step1 + COL_SIZE;
}
}
}
//Funzione che permette di fare il check di over and under population
char checkUnderAndOverPopulation(char *matrixrec, int currentRow, int currentColumn, int numbersOfRows, int numbersOfCols, int COL_SIZE) {
int viciniVivi = 0;
//Se la riga ha un indice maggiore di 0 ha sicuramente un vicino sopra di lei
if (currentRow > 0) {
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//Ho il vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn - 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//Ho il vicino destro
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn + 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
}
//Se la riga è minore del numero di righe-1, vuol dire che non è l'ultima ed ha un vicino sotto di lei
if (currentRow < numbersOfRows - 1) {
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//Se la colonna ha un indice maggiore di 0 sicuramente ha un vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn - 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//Se la colonna non è l'ultima ha sicuramente un vicino destro
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn + 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
}
//Se non sono presenti vicini top o bottom, controlliamo right or left
//Controllo vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow)*COL_SIZE) + (currentColumn - 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//Controllo vicino destro
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow)*COL_SIZE) + (currentColumn + 1)] == ALIVE) ? viciniVivi + 1 : viciniVivi;
//OverPopulation or UnderPopulation
return (viciniVivi > 3 || viciniVivi < 2) ? DEAD : ALIVE;
}
//Funzione che permette di controllare se una cella può riprodursi
char checkReproduction(char *matrixrec, int currentRow, int currentColumn, int numbersOfRows, int numbersOfCols, int COL_SIZE) {
int viciniVivi = 0;
//Se la riga ha un indice maggiore di 0 ha sicuramente un vicino sopra di lei
if (currentRow > 0) {
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Se la colonna ha un indice maggiore di 0 sicuramente ha un vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn - 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Se la colonna non è l'ultima ha sicuramente un vicino destro, Right neigh
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow - 1) * COL_SIZE) + (currentColumn + 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
}
//Se la riga è minore del numero di righe-1, vuol dire che non è l'ultima ed ha un vicino sotto di lei
if (currentRow < numbersOfRows - 1) {
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Se la colonna ha un indice maggiore di 0 sicuramente ha un vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn - 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Se la colonna non è l'ultima ha sicuramente un vicino destro
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow + 1) * COL_SIZE) + (currentColumn + 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
}
//Se non sono presenti vicini top o bottom, controlliamo right or left
//Controllo vicino sinistro
if (currentColumn > 0)
viciniVivi = (matrixrec[((currentRow)*COL_SIZE) + (currentColumn - 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Controllo vicino destro
if (currentColumn < numbersOfCols - 1)
viciniVivi = (matrixrec[((currentRow)*COL_SIZE) + (currentColumn + 1)]) == ALIVE ? viciniVivi + 1 : viciniVivi;
//Se il numero di viciniVivi è esattamente 3 la cella si riproduce altrimenti resta morta
return (viciniVivi == 3) ? ALIVE : DEAD;
}
//Funzione core che aggiorna la porzione di matrice di ogni processo
void gameUpdate(char *rebuildedMatrix, char *newMiniWorld, int numbersOfRows, int rank, int COL_SIZE) {
int offset_row_start = 1; //Indica da dove deve partire la computazione per evitare di computare anche le ghost cells
int offset_row_end = numbersOfRows + 1; //Indica il punto dove deve finire la computazione evitando le ghost cells //! ho fatto "+ 1" perché è come se avessi aggiunto anche la ghost cell iniziale e quindi devo saltarla. La utilizzo, ma non la computo.
for (int i = offset_row_start; i < offset_row_end; i++) {
for (int j = 0; j < COL_SIZE; j++) {
//Se la cella è viva, allora controllo se deve morire o sopravvivere alla generazione successiva
if (rebuildedMatrix[j + (i * COL_SIZE)] == ALIVE) {
//sottraendo offset_row_start ad i ottengo la posizione corretta di dove inserire nel newMiniWorld
newMiniWorld[j + ((i - offset_row_start) * COL_SIZE)] = checkUnderAndOverPopulation(rebuildedMatrix, i, j, offset_row_end + 1, COL_SIZE, COL_SIZE); //! ho fatto "+ 1" un'altra volta perchè è come se adesso avessi aggiunto anche la ghost cell finale. La utilizzo, ma non la computo.
//Se la cella è morta allora controllo se deve riprodursi
} else if (rebuildedMatrix[j + (i * COL_SIZE)] == DEAD) {
//sottraendo offset_row_start ad i ottengo la posizione corretta di dove inserire nel newMiniWorld
newMiniWorld[j + ((i - offset_row_start) * COL_SIZE)] = checkReproduction(rebuildedMatrix, i, j, offset_row_end + 1, COL_SIZE, COL_SIZE);
}
}
}
}
int main(int argc, char* argv[]) {
int my_rank;
int nprocs;
int tag = 10;
double start_time, end_time;
MPI_Status status;
MPI_Request requestTop, requestBottom;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
srand(1);
char *matrix; //Matrice generata
/*Ottengo i parametri in input, necessari per creare la matrice ed il numero di generazioni*/
int ROW_SIZE;
int COL_SIZE;
int choice = atoi(argv[1]); //Scelta della matrice da generare
int GENERATIONS = atoi(argv[2]); //Numero generazioni
switch (choice) {
case 1:
ROW_SIZE = 20;
COL_SIZE = 38;
break;
case 2:
ROW_SIZE = 19;
COL_SIZE = 21;
break;
default:
if (my_rank == 0)
fprintf(stderr, "\nNon esiste la choice: '%d'\nChoices disponibili: 1, 2.\n\nTERMINO IL PROGRAMMA\n", choice);
MPI_Finalize();
exit(0);
}
// In ricezione dalla MPI_Scatterv
char *matrixrec;
int dimMatrixRec = 0;
//Dati utili per la suddivisione in maniera equa (se possibile) della matrice
int *counts;
int *displacements;
int *rowPerProcess;
// Dati per la ricostruzione della matrice
char *rebuildedMatrix;
char *topRow, *bottomRow;
// Dati finali
char *newMiniWorld; //Porzione di matrice aggiornata
char *finalWorld; //Matrice che conterrà tutte le porzioni di matrici aggiornate
int root_rank = 0;
if (nprocs == 1) {
matrix = (char *)malloc((ROW_SIZE * COL_SIZE) * sizeof(char));
topRow = malloc(sizeof(char) * COL_SIZE);
bottomRow = malloc(sizeof(char) * COL_SIZE);
rebuildedMatrix = malloc(sizeof(char) * (ROW_SIZE + 2) * COL_SIZE); //Alloco spazio per la matrice che verrà ricostruita, aggiungendo semplicemente "+ 2" per le due righe nuove
finalWorld = malloc(sizeof(char) * (ROW_SIZE * COL_SIZE));
generateStaticMatrix(matrix, ROW_SIZE, COL_SIZE, choice);
start_time = MPI_Wtime();
for (int curr_generation=0; curr_generation<GENERATIONS; curr_generation++) {
memcpy(topRow, &matrix[0], COL_SIZE * sizeof(char));
memcpy(bottomRow, &matrix[(ROW_SIZE - 1) * COL_SIZE], COL_SIZE * sizeof(char));
//Ricostruisco la matrice
rebuildMatrix(matrix, ROW_SIZE, bottomRow, topRow, rebuildedMatrix, COL_SIZE);
//Aggiorno la matrice
gameUpdate(rebuildedMatrix, finalWorld, ROW_SIZE, my_rank, COL_SIZE);
if (my_rank == root_rank) {
printf("\n\tSTAMPA FINALE, CURR_GEN=%d\n", curr_generation+1);
printf("FinalWorld: \n");
printMatrixEmoji(finalWorld, ROW_SIZE, COL_SIZE);
printf("\n");
}
//Aggiorno matrix affinché venga utilizzata la matrice aggiornata nella generazione successiva
matrix = finalWorld;
}
}
else {
//Controllo se il numero di processi è maggiore del numero delle righe
MPI_Group world_group;
MPI_Comm_group(MPI_COMM_WORLD, &world_group);
MPI_Group new_group;
MPI_Comm new_comm;
if (nprocs > ROW_SIZE) {
int ranks_needed = nprocs > ROW_SIZE ? ROW_SIZE : nprocs;
int ranks[ranks_needed];
for (int i = 0; i < ranks_needed; i++) {
ranks[i] = i;
}
MPI_Group_incl(world_group, ranks_needed, ranks, &new_group);
MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
} else {
MPI_Comm_create(MPI_COMM_WORLD, world_group, &new_comm);
}
//Elimino i processi non necessari
if (new_comm == MPI_COMM_NULL) {
//printf("Process %d, muoio. ", my_rank);
MPI_Finalize();
return 0;
}
MPI_Comm_rank(new_comm, &my_rank);
MPI_Comm_size(new_comm, &nprocs);
//Controllo chi è il processo precedente e successivo
int next = (my_rank + 1) % nprocs;
int prev = (my_rank + nprocs - 1) % nprocs;
//Dati utili per la suddivisione in maniera equa (se possibile) della matrice
int count = ROW_SIZE / nprocs;
int remainder = ROW_SIZE % nprocs;
int rows;
counts = malloc(nprocs * sizeof(int)); //Array che conterrà il num. di elementi di ogni processo
displacements = malloc(nprocs * sizeof(int)); //Array che conterrà i displacements per ogni processo
rowPerProcess = malloc(nprocs * sizeof(int)); //Array che conterrà il numero di righe per ogni processo
/* ------------ START ------------*/
//Chiamata funzione di inizializzazione per displacement e send_counts per i processi
initDisplacementPerProcess(counts, displacements, rowPerProcess, nprocs, remainder, count, COL_SIZE);
matrixrec = malloc(sizeof(char) * (rowPerProcess[my_rank] * COL_SIZE)); //Alloco spazio per la matrice in ricezione
dimMatrixRec = rowPerProcess[my_rank] * COL_SIZE; //Calcolo dimensione della matrice in ricezione
//Inizializzazione delle variabili necessarie per l'invio delle righe ai processi adiacenti
newMiniWorld = malloc(sizeof(char) * (rowPerProcess[my_rank]) * COL_SIZE);
rows = rowPerProcess[my_rank]; //N. di righe della porzione di array ricevuta
topRow = malloc(sizeof(char) * COL_SIZE);
bottomRow = malloc(sizeof(char) * COL_SIZE);
rebuildedMatrix = malloc(sizeof(char) * (rowPerProcess[my_rank] + 2) * COL_SIZE); //Alloco spazio per la matrice che verrà ricostruita, aggiungendo semplicemente "+ 2" per le due righe nuove (ottenute dai processi adiacenti)
if(my_rank == root_rank) { //* MASTER
//Generazione iniziale e stampa della matrice
matrix = (char *)malloc((ROW_SIZE * COL_SIZE) * sizeof(char));
generateStaticMatrix(matrix, ROW_SIZE, COL_SIZE, choice);
finalWorld = malloc(sizeof(char) * (ROW_SIZE * COL_SIZE));
}
else { //TODO: SLAVE
/*VUOTO*/
}
start_time = MPI_Wtime();
//Invio e ricezione della porzione di matrice ad ogni processo
MPI_Scatterv(matrix, counts, displacements, MPI_CHAR, matrixrec, dimMatrixRec, MPI_CHAR, root_rank, new_comm);
for (int curr_generation=0; curr_generation<GENERATIONS; curr_generation++) {
MPI_Isend(&matrixrec[0], COL_SIZE, MPI_CHAR, prev, tag, new_comm, &requestTop); //Invio la riga al mio prev
MPI_Isend(&matrixrec[(rows - 1) * COL_SIZE], COL_SIZE, MPI_CHAR, next, tag, new_comm, &requestBottom); //Invio la riga al mio next
//Nel frattempo inizio a ricostruire la matrice inserendo quella centrale
rebuildMatrix2(matrixrec, 1, rows, NULL, NULL, rebuildedMatrix, COL_SIZE);
//Ricevo le righe dai processi adiacenti
MPI_Recv(bottomRow, COL_SIZE, MPI_CHAR, prev, tag, new_comm, &status); //Ricevo la riga dal mio prev
MPI_Recv(topRow, COL_SIZE, MPI_CHAR, next, tag, new_comm, &status); //Ricevo la riga dal mio next
//Ricostruisco la sottomatrice del processo aggiungendo le 2 righe ottenute dai processi adiacenti
if (prev == next) {
//Se ho due processi, next e prev coincidono quindi devo scambiare "topRow" con "bottomRow"
rebuildMatrix2(NULL, 0, rows, topRow, bottomRow, rebuildedMatrix, COL_SIZE);
}
else {
//Se ho più di due processi NON devo invertire "topRow" con "bottomRow"
rebuildMatrix2(NULL, 0, rows, bottomRow, topRow, rebuildedMatrix, COL_SIZE);
}
//Chiamo la funzione principale "gameUpdate" per aggiornare le matrici (e quindi sto aggiornando il gioco)
gameUpdate(rebuildedMatrix, newMiniWorld, rows, my_rank, COL_SIZE);
//Restituisco la matrice finale contenuta in finalWorld al master per la stampa
MPI_Gatherv(newMiniWorld, counts[my_rank], MPI_CHAR, finalWorld, counts, displacements, MPI_CHAR, root_rank, new_comm);
if (my_rank == root_rank) {
printf("\n\tSTAMPA FINALE, CURR_GEN=%d\n", curr_generation+1);
printf("FinalWorld: \n");
printMatrixEmoji(finalWorld, ROW_SIZE, COL_SIZE);
printf("\n");
}
//Adesso aggiorno matrixrec affinché venga utilizzata la porzione aggiornata della matrice nella generazione successiva
matrixrec = newMiniWorld;
}
}
end_time = MPI_Wtime();
/*-------------FINE-------------*/
//libero spazio
if (nprocs == 1) {
free(rebuildedMatrix);
free(topRow);
free(bottomRow);
free(matrix);
}
else {
free(counts);
free(displacements);
free(rowPerProcess);
free(matrixrec);
free(rebuildedMatrix);
free(topRow);
free(bottomRow);
if (my_rank == root_rank) {
free(finalWorld);
free(matrix);
}
}
if (my_rank == root_rank) {
printf("\nNprocs: %d, Time in seconds=%f\n", nprocs, end_time - start_time);
}
MPI_Finalize();
return 0;
}